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

 
ReentrantLock加锁流程
加锁成功流程


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

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

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

ReentrantLock解锁后是怎么竞争的?
解锁竞争成功



- 设置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加锁流程
加锁成功
- 将state设置为1。
- 设置ExclusiveOwnerThread为当前线程。
加锁失败
- 进入tryAcquire逻辑,如果state已经是1,则失败。
- 进入addWaiter逻辑,构造Node队列。 - Node的创建是懒惰的。
- 第一个Node成为Dummy,不关联线程。
 
- 当前线程进入acquireQueued逻辑。 - 在死循环中尝试获取锁,失败则进入park阻塞。
- 如果自己紧邻着head(排第二位),再次尝试tryAcquire获取锁。
- 将前驱node(head)的waitStatus设置为-1。
- 进入parkAndCheckInterrupt,线程park。
 
ReentrantLock解锁后的竞争
解锁竞争成功
- 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。
 
解锁竞争失败
- 如果有其他线程(如Thread-4)竞争。 - Thread-4可能抢先设置为exclusiveOwnerThread,state为1。
- Thread-1再次进入acquireQueued流程,获取锁失败,重新进入park阻塞。
 
这篇文档详细描述了ReentrantLock在加锁和解锁过程中的内部机制,包括状态的变更、队列的构造、线程的阻塞和唤醒等关键步骤。
 
如果我的内容对你有帮助,请辛苦动动您的手指为我点赞,评论,收藏。感谢大家!!
 
