ReentrantLock.condition流程图
2019-06-28 10:01:52 2 举报
ReentrantLock Condition条件队列流程
作者其他创作
大纲/内容
fullyRelease(node)release(savedState)tryRelease(arg)
(node.waitStatus == Node.CONDITION || node.prev == null)?
interruptMode = REINTERRUPT
唤醒线程来自signal()
falseCAS 失败,肯定是因为 signal 方法已经将 waitStatus 设置为了 0
isOnSyncQueue(node)
true自旋进入阻塞队列的队尾
false转移后面一个节点
将node加入条件队列
true前驱节点取消了等待锁唤醒线程
true
doSignal(first)
interruptMode == THROW_IE
CAS成功当前线程将在在阻塞队列中等待
(node.nextWaiter != null)
false
结束
node的后直接点不为空说明在同步队列中
发生异常,释放失败(有可能没有持有锁却释放执行释放操作)也从侧面证明,如果要执行await要先获得锁
addConditionWaiter 封装当前节点加入条件队列
LockSupport.unpark(node.thread);
线程是否持有当前的独占锁
while (!isOnSyncQueue(node))要么中断,要么转移成功才退出循环
false条件队列为空,没有要唤醒
throw new InterruptedException()
false将节点从条件队列转移到阻塞队列成功
!transferForSignal(first)?
中断状态:REINTERRUPT: 代表 await 返回的时候, 需要重新设置中断状态THROW_IE: 代表 await 返回的时候, 需要抛出 InterruptedException 异常0 :说明在 await 期间,没有发生中断
因为 first 节点马上要离开了所有要将当前firstWaiter指向下一个
如果为false:明此 node 的 waitStatus 已不是 Node.CONDITION此节点已经取消,也就不需要转移了,那么就转移后面一个节点如果为true:将node的waitStatus 置为 0
enq(node)
LockSupport.park(this)后可能继续执行的情况常规路径:signal -> 转移节点到 阻塞队列 -> 获取了锁(unpark)线程中断:在 park 的时候, 另外一个线程对这个线程进行了中断假唤醒:这个也是存在的, 和 Object.wait() 类似,都有这个问题
unlinkCancelledWaiters()
当新的节点要加入条件队列时,会将waitStatus = CANCELLED的节点清除,这也是CANCELLED节点的来源
true first后面的第一个节点不为null循环操作
transferAfterCancelledWait(node)?判断中段时间
响应中断
将节点从条件队列转移到阻塞队列
unlinkCancelledWaiters()
node.waitStatus = Node.CANCELLED将当前节点的waitStatus置为CANCELLED
first离开后断开与条件队列的联系
从阻塞队列的tail开始往前遍历,查找node时都在阻塞队列中
清除waitStatus被取消的节点
waitStatus 为CONDITION或者节点的前驱结点为空说明在条件队列中,不在同步队列中
trueCAS 失败唤醒线程
tryRelease(arg)Exception?
await()
true代表在 signal 之前,节点已经取消了,此时节点first转移失败那么选择 first 后面的第一个节点进行转移
interrupted()?
interruptMode
findNodeFromTail(node)
直接唤醒该线程
true移除取消节点
封装当前线程为Node
ws > 0 说明 node 在阻塞队列中的前驱节点取消了等待锁,直接唤醒 node 对应的线程。
lastWaiter.nextWaiter = node;lastWaiter = node
这一步入阻塞队列的的时候,并没有node.nextWaiter = null的操作
true不持有锁
checkInterruptWhileWaiting(node)?
(firstWaiter = first.nextWaiter) == null?
返回的是node的前前驱节点
true将 first 移除后,后面无节点在等待,那么需要将 lastWaiter 置为 null
signal 调用之后,没完成转移之前,发生了中断
throw new IllegalMonitorStateException
具体实现
释放持有的所有锁
是否要移除条件队列中取消节点
isOnSyncQueue(node)?
interruptMode=0
false说明不在阻塞队列中
ws > 0?
状态置为CANCELLED
检查中断状态
!isHeldExclusively()?
释放锁结果
true说明发生了中断,并且不是在signal之前发生了中断
fullyRelease(node)
selfInterrupt()
interruptMode=THROW_IE
first.nextWaiter = null
false当前线程持有独占锁
否
当前节点是否在阻塞(同步)队列中?
用 CAS 将节点状态设置为 0
interruptMode != 0?
是否重新中断
true发生过中断
signal
lastWaiter = null
interruptMode == REINTERRUPT
addConditionWaiter
实现过程
true/false
(first = firstWaiter) != null?
确定interruptMode的值
firstWaiter!= null?
从条件队列队头往后遍历,找出第一个需要转移的 node
判断是否要重新中断
interruptMode=REINTERRUPT
ture
Thread.interrupted() ?(前线程是否被终端)
(node.next != null) ?
true条件队列不为空唤醒firstWaiter
signal()
LockSupport.park(this)挂起当前线程
0 条评论
回复 删除
下一页