当前位置: 首页 > news >正文

ReentrantLock【复习】

ReentrantLock lock = new ReentrantLock(1/0)

如果创建的时候是设置的1就是创建的公平锁,如果是0默认那么就是非公平锁。

1.公平锁加锁

        首先先获取加锁执行lock()方法,会进行acquire操作,acquire里有一个tryAcquire,先判断它是不是成功,如果是成功说明加锁成功就不会进行后续操作,如果是加锁失败,那么取反是true,就会进行下次的操作acquireQueued这个里面会先进性addWaiter方法将线程Node加入阻塞队列,这也是AQS的一个主要体现,如果加成功了会执行外面的acquireQueued操作。

        tryAcquire里会先获取state状态如果是0就是证明这个锁还是空闲状态,如果是1证明这把锁已经被人用了,如果是1证明是被人用了,还会进行一个判断,看看这个把锁是不是自己当前线程的,如果是自己当前线程的那么那么会将state+1,也就是说这个state不止有0或1这个状态,还有可能有123456,这也就是可重入锁的体现。如果此时判断state是0,证明锁没被人用,正常来说此时应该进行CAS将锁的状态由0改成1证明锁被人使用了然后设置锁的使用者为当前线程,但是因为这是公平锁,所以会先判断如果没人在队列中排队才会进行CAS加锁,如果加锁失败了或者队列中有人等待那么会将该线程加入阻塞队列中。判断有没有人在阻塞队列就是先判断头结点和尾节点是不是相等,如果是相等证明是null,说明阻塞队列中没有元素,如果判断头节点的下一个节点是是自己当前线程,如果是证明是一个可重入锁,那么会返回false,否则返回true,或者判断头节点的下一个节点是不是null,如果是null此时证明有可能是多线程情况下,加入队列的两个节点,第一个节点可能还没有将头节点的next想连,此时第二个节点也加入队列,判断head.next是不是null,如果是null证明此时阻塞队列有元素,考虑到并发勤快了。如果判断有人在等待或者加锁失败,则会退出这个tryAcquire方法。进行acquireQueued里的addwaiter方法,将当前线程加到AQS里的双向队列节点后面,如果此时有5个线程同时加队列,然后都发现队列有元素证明有人在等待,那么就会进行争抢看谁先入队成功,剩下4没成功的就会执行enq方法,这里面是一个while操作,直到自己的线程加入到队列才能结束,保证此时线程都能加入队列。加入队列这个操作有个注意的就是如果加入队列的时候这里面是空的,证明该线程是第一个加入节点的,那么此时不会把该线程当成第一个节点,而是创造一个空节点,然后将该线程设置节点加入上一个空节点的下一个节点上,目的就是为了,如果是第一个线程解锁成功了,然后队列中有一个节点,那么第一个线程解锁成功会唤醒队列中head.next这个节点,那么这个节点就可以争取锁了。然后进入acquireQueued方法里会进入一个循环,然后里面会判断当前加入的节点的前一个节点是不是刚才创建的那个空的头节点,如果是的话说明这个节点是阻塞队列里面唯一的线程节点,那么允许他再进行获取一次锁,如果此时获取锁成功了那么就将当前节点置空,然后设置为新的头节点以供下次线程加锁失败加入该队列时候使用。如果获取锁失败执行下面的判断,如果获取当前节点的上一个节点的waitstatus是不是-1如果不是-1会将它改成-1然后返回false,会进行再一轮循环,如果此时还是加锁失败,那么继续进行刚才的if判断,此时判断上一个节点的waitstatus是-1了,那么就将这个线程阻塞等待park()。如果被唤醒,则继续循环,直到阻塞队列只剩下头节点以及线程的节点了,那么此时线程获取锁成功后会将头结点清理断开循环GC垃圾回收器回收掉。

2.非公平锁加锁

        调用lock()方法上来先进行加锁,加到锁将持有线程改成当前线程。如果一上来没有加到锁,那么会进入acquire方法,调用tryAcquire方法这个是非公平锁的视线,他这里就直接判断state是不是等于0.如果等于0那么直接就加锁,不许要判断之前公平锁里那样看阻塞队列里有没有线程存在。如果不等于0判断是不是当前线程如果是就是可重入锁,state+1,如果加锁失败了,就返回false。之后退出这个方法接下来就像公平锁一样,会将该任务加入到队列中接下来和公平锁一样。

3.解锁

        不论公平锁还是非公平锁,他们的解锁都是一致的,并且他们解锁其实都是公平解锁。执行unlock()方法会进入release方法,此时公平锁和非公平锁的逻辑是统一的。实际上就是该state,不断的-1目的是防止可重入锁,直到为0证明这个锁结束然后回到release方法进行unpark解除阻塞。当然还有细节方面的比如中断的时候节点的waitstatus会是1,那么此时解锁的时候就会跳过这些waitstatus1的节点。


http://www.mrgr.cn/news/69719.html

相关文章:

  • HarmonyOS Next 组件或页面之间的所有通信(传参)方法总结
  • 《物理学报》
  • Kafka简单实践
  • 【R语言】字符类型转换
  • 如何在vscode 中打开新文件不覆盖上一个窗口
  • 大数据新视界 -- 大数据大厂之 Impala 性能飞跃:动态分区调整的策略与方法(上)(21 / 30)
  • 微服务(二)
  • AI背后的“思考者“:LLM大语言模型是什么?
  • 使用热冻结数据层生命周期优化在 Elastic Cloud 中存储日志的成本
  • 一定要chatgpt吗?
  • 十八:Spring Boot 依赖(3)-- spring-boot-starter-data-jpa 依赖详解
  • 对静态资源加载失败的场景做降级处理
  • 防倒灌电路【手电钻工作日志】
  • 素数筛选法
  • 说说HDD老将的那些事儿
  • 这是我见过讲解大模型最详细的一本书!学习大模型的建议都去读!
  • 拓扑学与DNA双螺旋结构的奇妙连接:从算法到分子模拟
  • 大模型入门自学资源汇总,很难找到比这还全的大模型学习资源总结了!
  • <项目代码>YOLOv8 草莓成熟识别<目标检测>
  • 【存储服务】一文带你了解ETCD
  • 政治经济学笔记
  • 从关键新闻和最新技术看AI行业发展(第三十四期2024.10.14-10.27) |【WeThinkIn老实人报】
  • 计算机网络——1.1计算机网络概述
  • PG COPY 与 INSERT方式导入数据时, 表默认值表现的不同
  • 【日志框架整合】Slf4j、Log4j、Log4j2、Logback配置模板
  • Linux系统常用命令