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

ReentrantLock 加锁与解锁流程详解(源码分析,小白易懂)

在这里插入图片描述

👨‍💻程序员三明治:个人主页

🔥 个人专栏: 《设计模式精解》 《重学数据结构》

🤞先做到 再看见!

ReentrantLock加锁流程

加锁成功流程

其实就是把state改为1,然后设置ExclusiveOwnerThread为当前线程** 加锁失败流程**

  1. 进入tryAcquire逻辑,这是state已经是1,结果仍然失败
  2. 接下来进入addWaiter逻辑,构造Node队列
    • 下图中黄色三角表示该Node的waitStatus状态,其中0为默认正常状态
    • Node的创建是懒惰的
    • 其中第一个Node成为Dummy,用来占位,并不关联线程


当前线程进入acquireQueued的逻辑

  1. acquireQueued会在第一个死循环中不断尝试获得锁,失败后进入park阻塞
  2. 如果自己紧邻着head(排第二位),那么再次tryAcquire尝试获取锁,当然这时state仍为1,失败
  3. 进入shouldParkAfterFailedAcquire逻辑,将前驱node,即head的waitStatus改为-1,这次返回false

  1. shouldParkAfterFailedAcquire执行完毕回到acquireQueued(因为是死循环),再次tryAcquire尝试获取锁,当然这时state仍为1,失败
  2. 当再次进入shouldParkAfterFailedAcquire时,这是因为其前驱node的waitStatus已经是-1,这次返回true
  3. 进入parkAndCheckInterrupt,Thread-1 park(灰色表示)

ReentrantLock解锁后是怎么竞争的?

解锁竞争成功

![](https://i-blog.csdnimg.cn/img_convert/4c547a6c8ffabfa86196b1891fd977ea.png)

此时Thread-0释放锁,进入tryRelease流程,如果成功
  • 设置exclusiveOwnerThread为null
  • state=0

  • 当前队列不为null,并且head的waitStatus=-1,进入unparkSuccessor流程
  • 找到队列中离head最近的一个Node(没取消的),unpark恢复其运行,本例中即为Thread-1
  • 回到Thread-1的acquireQueued流程


此时Thread-1的Node在下一次进入循环的时候发现tryAcquire成功了,会设置

- <font style="color:rgb(38, 38, 38);">exclusiveOwnerThread为Thread-1,state=1</font>
- <font style="color:rgb(38, 38, 38);">head指向刚刚Thread-1所在的Node,该Node清空Thread</font>
- <font style="color:rgb(38, 38, 38);">原本的head因为从链表断开,可以被垃圾回收</font>

解锁竞争失败
如果这时候有其他线程来竞争(非公平的体现),例如这时有Thread-4来了


如果不巧又被Thread-4抢先

- <font style="color:rgb(38, 38, 38);">Thread-4被设置为exclusiveOwnerThread,state=1,</font>
- <font style="color:rgb(38, 38, 38);">Thread-1再次进入acquireQueued流程,获取锁失败,重新进入park阻塞</font>

总结

这篇文档主要介绍了Java中ReentrantLock的加锁和解锁流程,包括成功和失败的情况。以下是文档的重点概括:

ReentrantLock加锁流程

加锁成功
  1. 将state设置为1。
  2. 设置ExclusiveOwnerThread为当前线程。
加锁失败
  1. 进入tryAcquire逻辑,如果state已经是1,则失败。
  2. 进入addWaiter逻辑,构造Node队列。
    • Node的创建是懒惰的。
    • 第一个Node成为Dummy,不关联线程。
  3. 当前线程进入acquireQueued逻辑。
    • 在死循环中尝试获取锁,失败则进入park阻塞。
    • 如果自己紧邻着head(排第二位),再次尝试tryAcquire获取锁。
    • 将前驱node(head)的waitStatus设置为-1。
    • 进入parkAndCheckInterrupt,线程park。

ReentrantLock解锁后的竞争

解锁竞争成功
  1. Thread-0释放锁,进入tryRelease流程。
    • 设置exclusiveOwnerThread为null。
    • state设置为0。
    • 如果当前队列不为null,并且head的waitStatus为-1,进入unparkSuccessor流程。
    • 找到队列中离head最近的一个Node(未取消的),unpark恢复其运行(例如Thread-1)。
    • Thread-1的Node在下一次循环时发现tryAcquire成功,设置exclusiveOwnerThread为Thread-1,state为1,head指向Thread-1所在的Node。
解锁竞争失败
  1. 如果有其他线程(如Thread-4)竞争。
    • Thread-4可能抢先设置为exclusiveOwnerThread,state为1。
    • Thread-1再次进入acquireQueued流程,获取锁失败,重新进入park阻塞。

这篇文档详细描述了ReentrantLock在加锁和解锁过程中的内部机制,包括状态的变更、队列的构造、线程的阻塞和唤醒等关键步骤。





如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!
在这里插入图片描述

http://www.dtcms.com/a/548525.html

相关文章:

  • 鸿蒙Flutter三方库适配指南:06.插件适配原理
  • Linux 防火墙实战:用 firewalld 配置 External/Internal 区域,实现 NAT 内网共享上网
  • Java 学习29:方法
  • Kafka 全方位详细介绍:从架构原理到实践优化
  • Obsidian 入门教程(二)
  • [测试工具] 如何把离线的项目加入成为git项目的新分支
  • 让数据导入导出更智能:通用框架+验证+翻译的一站式解决方案
  • 今天我们学习Linux架构keepalived实现LVS代理双击热备
  • [Linux]内核队列实现详解
  • 【Spring Cloud】Spring Cloud Config
  • MySQL | 数据查询DQL语言:分组统计
  • 阿里云灵码IDE技术测评:从v0.1.0到v0.1.5的进化之路
  • 江门网站推广技巧asp网站服务建设
  • C++: inline 与 ODR,冲突的诞生
  • 营销型 展示类网站企业网站建设空间
  • 从单体到微服务:Java的分布式演进与工程实战
  • 【论文笔记】扩散模型——如何通俗理解传统概率模型的核心矛盾
  • android15 实现截屏功能
  • 工业4.0数据中枢:重构产品全生命周期的智能设计范式
  • 深度解析《AI+Java编程入门》:一本为零基础重构的Java学习路径
  • 架构论文《论数字孪生系统架构设计与应用》
  • 郑州网站建设汉狮如何让百度收录自己的网站信息
  • 英一2017年真题学习笔记
  • PaddleOCR-VL对标DeepSeek-OCR?
  • DeepSeek-OCR 论文精读与实践:用“光学上下文压缩”把长文本变成图片,再由 VLM 高效还原
  • 创新网站内容建设企业建网站的案例
  • 沈阳建站模板系统包括如何自己创建一个网页
  • NLP模型优化
  • 运行当前位置,显示文件全名,检查是否扩展名多次重叠
  • 基于ubuntu22构建spark镜像 —— 筑梦之路