ReentrantLock图解
2020-12-14 15:19:06 2 举报
AQS,ReentrantLock图解
作者其他创作
大纲/内容
exclusiveOwnerThread
假设 Thread-1 要来唤醒 Thread-0
锁重入state++
lastWaiter
Node(null)
Node(thread-2)
state=1
null
firstWaiter
0
Thread-0 释放锁,进入 tryRelease 流程,如果成功设置 exclusiveOwnerThread 为 nullstate = 0
head
thread-0
thread-0释放锁
Node(thread-3)
-1
thread-1加锁(没有竞争)
tail
如果这时候有其它线程来竞争(非公平的体现),例如这时有 Thread-4 来了如果不巧又被 Thread-4 占了先Thread-4 被设置为 exclusiveOwnerThread,state = 1Thread-1 再次进入 acquireQueued 流程,获取锁失败,重新进入 park 阻塞
Node(thread-0)
font color=\"#ff3333\
//32位的状态变量private volatile int state;//head节点private transient volatile Node head;//tail节点private transient volatile Node tail;//加锁成功,指向获得锁的Threadprivate transient Thread exclusiveOwnerThread;
Node(thread-1)
Node(thread-0)
当前线程进入 acquireQueued 逻辑1. acquireQueued 会在一个死循环中不断尝试获得锁,失败后进入 park 阻塞2. 如果自己是紧邻着 head(排第二位),那么再次 tryAcquire 尝试获取锁,当然这时 state 仍为 1,失败3. 进入 shouldParkAfterFailedAcquire 逻辑,将前驱 node,即 head 的 waitStatus 改为 -1,这次返回 false
争抢锁,因为队列中有节点(Thread-1),所以失败
state=0
AQSAbstractQueuedSynchronizer
await 流程开始 Thread-0 持有锁,调用 await,进入 ConditionObject 的 addConditionWaiter 流程创建新的 Node 状态为 -2(Node.CONDITION),关联 Thread-0,加入等待队列尾部
再次有多个线程经历上述过程竞争失败,变成这个样子
thread-1加锁(有竞争,没竞争过)
thread-1争抢锁失败,进入acquireQueued流程
Thread-1 执行了1. CAS 尝试将 state 由 0 改为 1,结果失败2. 进入 tryAcquire 逻辑,这时 state 已经是1,结果仍然失败3. 接下来进入 addWaiter 逻辑,构造 Node 队列图中黄色三角表示该 Node 的 waitStatus 状态,其中 0 为默认正常状态Node 的创建是懒惰的其中第一个 Node 称为 Dummy(哑元)或哨兵,用来占位,并不关联线程
signal 流程
可重入可打断支持公平锁需要手动加锁和释放锁支持多个条件变量
thread-2
具体参考这个学习:https://blog.csdn.net/nmjhehe/article/details/109787603
NULL
条件变量原理
-2
thread-0获得锁
await 流程
state=2
Node(thread-4)
thread-0锁重入
被回收
4. shouldParkAfterFailedAcquire 执行完毕回到 acquireQueued ,再次 tryAcquire 尝试获取锁,当然这时state 仍为 1,失败5. 当再次进入 shouldParkAfterFailedAcquire 时,这时因为其前驱 node 的 waitStatus 已经是 -1,这次返回true6. 进入 parkAndCheckInterrupt, Thread-1 park(灰色表示)
如果加锁成功(没有竞争),会设置exclusiveOwnerThread 为 Thread-1,state = 1head 指向刚刚 Thread-1 所在的 Node,该 Node 清空 Thread原本的 head 因为从链表断开,而可被垃圾回收
公平锁实现原理
unpark AQS 队列中的下一个节点,竞争锁,假设没有其他竞争线程,那么 Thread-1 竞争成功同时阻塞线程thread-0
接下来进入 AQS 的 fullyRelease 流程,释放同步器上的锁
5. 条件变量实现原理每个条件变量其实就对应着一个等待队列,其实现类是 ConditionObject
进入 ConditionObject 的 doSignal 流程,取得等待队列中第一个 Node,即 Thread-0 所在 Node执行 transferForSignal 流程,将该 Node 加入 AQS 队列尾部,将 Thread-0 的 waitStatus 改为 0,Thread-3 的waitStatus 改为 -1
0 条评论
下一页