addConditionWaiter() 方法是封装一个节点将该节点放入条件队列中
private Node addConditionWaiter() { Node t = lastWaiter; // If lastWaiter is cancelled, clean out. // 如果尾节点被cancel了,则先遍历整个链表,清除所有被cancel的节点 if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } // 将当前线程包装成Node扔进条件队列 Node node = new Node(Thread.currentThread(), Node.CONDITION); // 如果当前节点为空值那么新创建的node节点就是第一个等待节点 if (t == null) firstWaiter = node; // 如果当前节点不为空值那么新创建的node节点就加入到当前节点的尾部节点的下一个 else t.nextWaiter = node; lastWaiter = node; // 尾部节点指向当前节点 return node; // 返回新加入的节点 }注意:
节点加入条件队列时waitStatus的值为Node.CONDTION。
如果入队时发现尾节点已经取消等待了,那么我们就不应该接在它的后面,此时需要调用unlinkCancelledWaiters来清除那些已经取消等待的线程(条件队列从头部进行遍历的,同步队列是从尾部开始遍历的)
private void unlinkCancelledWaiters() { // 获取队列的头节点 Node t = firstWaiter; Node trail = null; // 当前节点不为空 while (t != null) { // 获取下一个节点 Node next = t.nextWaiter; // 如果当前节点不是条件节点 if (t.waitStatus != Node.CONDITION) { // 在队列中取消当前节点 t.nextWaiter = null; if (trail == null) // 队列的头节点是当前节点的下一个节点 firstWaiter = next; else // trail的 nextWaiter 指向当前节点t的下一个节点 // 因为此时t节点已经被取消了 trail.nextWaiter = next; // 如果t节点的下一个节点为空那么lastWaiter指向trail if (next == null) lastWaiter = trail; } else // 如果是条件节点 trail 指向当前节点 trail = t; // 循环赋值遍历 t = next; } }fullyRelease(node) 方法释放当前线程所占用的锁
final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); // 如果释放成功 if (release(savedState)) { failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) // 节点的状态被设置成取消状态,从同步队列中移除 node.waitStatus = Node.CANCELLED; } } public final boolean release(int arg) { // 尝试获取锁,如果获取成功,唤醒后续线程 if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }线程唤醒后利用checkInterruptWhileWaiting方法检测中断模式
情况一中断发生时,线程还没有被唤醒过
这里假设已经发生过中断,则Thread.interrupted()方法必然返回true,接下来就是用transferAfterCancelledWait进一步判断是否发生了signal。
// 检查是否有中断,如果在发出信号之前被中断,则返回THROW_IE; // 在发出信号之后,则返回REINTERRUPT;如果没有被中断,则返回0。 private int checkInterruptWhileWaiting(Node node) { return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; } final boolean transferAfterCancelledWait(Node node) { if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; } while (!isOnSyncQueue(node)) Thread.yield(); return false; } 只要一个节点的waitStatus还是Node.CONDITION,那就说明它还没有被signal过。
由于现在我们分析情况1,则当前节点的waitStatus必然是Node.CONDITION,则会成功执行compareAndSetWaitStatus(node, Node.CONDITION, 0),将该节点的状态设置成0,然后调用enq(node)方法将当前节点添加进同步队列中,然后返回true。