condictionObject相当于Monitor的waitSet。
每个条件变量对应一个conditionObject这个对象,这个对象在sync里面的,内部也是维护了一个双向链表的。
await流程和signal流程。
这个方法就是线程加入到条件变量的双向链表里面去。
都是加入到队列的尾部的。
可知:
---
看下这个方法:
接下来:
这个方法是当前的节点就是thread-0线程上的所有锁都释放掉,就是进入wait的节点,和wait是一样的,包括锁重入的次数。
这个saveStated是所有的锁重入的次数。
唤醒等待队列的离头节点最近的下一个节点,竞争。
进入release方法。
唤醒头结点的下一个节点。
这里unpark就解除阻塞了,进入到acquireQueue得方法继续执行:
接下来进入park状态,等待被唤醒。
while循环我们不管它。
---245---
假设这个场景:
Thread-1是锁得持有者,thread-0在条件变量里面等待的。
调用singal的线程必须是锁的持有者。
signal方法:
首先检查调用signal的方法是不是锁的持有者,不是就直接抛出异常,只有owner才有资格去唤醒得。
找条件变量等待队列里面的头的元素,不为空就调用doSignal方法。
注意:链表有多个元素的话也不是随机的去调用,总是调用队首的元素。
进入doSingnal方法,做了哪两件事?第一件事就是在条件变量的队列去掉头,然后把头加到等待队列里面去。
转移失败就找下一个节点。
这个方法主要是使节点在条件变量这个链表断开,重新竞争锁,加入到等待锁的这个链表中。
第一个waiter=第一个waiter的nextWaiter。
指向null,在条件变量这个链表中断开。
进入这个方法,节点注意到竞争锁的队列:
节点转移到竞争锁的链表,就是等待队列的。转移失败的话唤醒下一个节点。
为什么会转移失败呢?可能会被打断或者取消的。
---
进入transferForSingal方法:
这里为什么改为0。因为加入到条件变量这个链表中这个状态就变成了-2了。加入到锁的竞争队列里面最后一个节点,总是为0。
进入到这个方法:
进入,把节点加到等待队列的尾部。
将节点加入到等待队列的尾部。成功了返回前驱节点。
看下前驱结点并改为-1
再来:
再来:进入acquireQueue方法。
检查前驱节点的状态。改为-1,有责任唤醒链表的下一个元素。
流程分析:
源码解析:
---246---