Condition
基本使用:
ReentrantLock lock = new ReentrantLock();
lock.lock();
Condition condition = lock.newCondition();
condition.await();
condition.notify()
备注 :这里需要注意的是, 想使用condition.await()方法,代表此线程一定是获取到的锁,才能await() 。 否则跑出异常。
开始查看一下源码 :
a . 如果此线程被发出过终止的指令, 这里直接抛出常见的 InterruptedException 。
b . 跟同步队列一样, 那里是增加waiter. addWaiter()方法,这里是 addConditionWaiter()方法。还是比较贯通的。
c . 查看 addConditionWaiter() 方法
a . 如果是刚创建这个Condition 单向列表。同样是一个线程一个Node节点。初始化的时候,这个Node的 Thread 属性为 Thread.currentThread() , waitStatus = -2 (Node.CONDITION) 。
b . firstWaiter 也指向这个线程Node. 又因为这个Node是新增的,所以它也是lastWaiter。
备注: 同步链表 : 因为会存在抢占锁, 第一个进入同步列表的线程其实已经是第二个进入这个流程的线程了。所以会存在一个Head = new Node()。相当于表示那个抢占锁成功的线 程。
Condition链表: 只要一个抢占到锁的线程,调用await()方法,就直接进入Condition链表。 所以这个firstWaiter 就是 当前线程的Node.
c . 返回当前线程的Node。
d . 继续往下看,int savedState = fullyRelease(node) 。
a . fullRelease().意思是就算重入,这里也要把state释放为0。同时释放成功后,唤醒当前释放线程的 next Node。
b . 查看 2个方法 。 int savedState = getState() , release(savedState) 。
a . 这里是把所有重入的次数都减了。如果这个节点Node释放锁失败,就直接把这个节点置为Cancle.
b . 锁释放成功。while (!isOnSyncQueue(node)) 开始查看这个进入条件(是否还存在在同步队列中)。
a . 第一个if , 如果这个节点的waitStatus = Condition (-2) , 如果是同步队列,那么这个waitStatus = Signal (-1) 。所以这个代表已经不在同步队列中了。
|| return false ;
b . if (node.next != null) 如果当前线程的Node节点.next 节点不为空, 肯定代表在同步链表上 , 因为Condition链表没有设置 prev 和 next 。 只有 nextWaiter 。 return true 。
c . findNodeFromTail(node)
a . 开始一个死循环判断,这就是我们说的,查看一个元素是否存在在同步队列中,都是从尾部开始往前查找, 使用Node.prev 往前看。 如果不存在。 返回fasle。 存在 返回true 。
b. 如果增方法返回为false。 就是不存在在同步队列上了, 就可以把这个线程挂起了。 采用的还是 LockSupport.park(this)了 。