首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ReentrantLock 加锁与解锁流程详解(源码分析,小白易懂)

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

作者头像
程序员三明治
发布2025-12-18 20:46:45
发布2025-12-18 20:46:45
820
举报
文章被收录于专栏:码力up码力up

🤞先做到 再看见!


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成功了,会设置

代码语言:javascript
复制
- <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抢先

代码语言:javascript
复制
- <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在加锁和解锁过程中的内部机制,包括状态的变更、队列的构造、线程的阻塞和唤醒等关键步骤。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • ReentrantLock加锁流程
  • ReentrantLock解锁后是怎么竞争的?
  • 总结
    • ReentrantLock加锁流程
    • ReentrantLock解锁后的竞争
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档