volatile int waitStatus; static final int CANCELLED = 1; static final int SIGNAL = -1; static final int CONDITION = -2; static final int PROPAGATE = -3;
finalbooleanisOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) returnfalse; if (node.next != null) // If has successor, it must be on queue returntrue; /* * node.prev can be non-null, but not yet on queue because * the CAS to place it on queue can fail. So we have to * traverse from tail to make sure it actually made it. It * will always be near the tail in calls to this method, and * unless the CAS failed (which is unlikely), it will be * there, so we hardly ever traverse much. */ // 从同步等待队列的尾部开始向上查找是否存在这个node return findNodeFromTail(node); }
/** * 从同步队列的尾部开始向前遍历,如果找到就返回true,否则false */ privatebooleanfindNodeFromTail(Node node) { Nodet= tail; for (;;) { if (t == node) returntrue; if (t == null) // 这个就是到头了,到头还没找到就返回false returnfalse; t = t.prev; } }
finalbooleantransferForSignal(Node node) { /** * If cannot change waitStatus, the node has been cancelled. * * 就是把 Node 的 waitStatus 从 CONDITION 状态变成 0 * 如果CAS失败的话,那 waitStatus就被修改过,就不等于CONDITION,也就只能是 CANCELLED */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) returnfalse;
/* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */ /** * enq(node) 上次分析过,就是把node CAS添加到同步等待队列的尾部,并返回node的前驱节点 * 为什么要返回前驱节点呢?还记得 之前分析过的 shouldParkAfterFailedAcquire() 把前驱节点的waitStatus 设置成SIGNAL * 表示同步队列中还有线程在等待,你记得唤醒我!!! */ Nodep= enq(node); intws= p.waitStatus; // 如果已经ws>0 说明前驱节点已经被取消 或者 CAS修改状态失败 唤醒当前线程 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); returntrue; }
finalbooleantransferAfterCancelledWait(Node node) { // 只要一个节点的waitStatus还是Node.CONDITION,那就说明它还没有被signal过 if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { /** * 如果没有被signal,说明是中断唤醒的,enq(node)把节点从条件等待队列移动到同步队列并返回true. * 这里注意一点就是和正常signal 不同的是,我们这里没有把 nextWaiter 设置为null * 也就是还和条件等待队列关联着 */ enq(node); returntrue; } /* * If we lost out to a signal(), then we can't proceed * until it finishes its enq(). Cancelling during an * incomplete transfer is both rare and transient, so just * spin. */ /** * 因为不管是正常signal还是中断唤醒,最终都会移动到同步队列 * 一直自旋判断是否移动到同步队列,没有则Thread.yield()把CPU让给其他线程,不一定让步成功,可能自己又抢到了 * * 而代码能走到这里说明上面的CAS更新失败,也就是在其他地方(signal)已经把node移动到同步队列 * 说明signal 和中断 基本上是同时发生的,但最终还是中断来得太晚,返回false,重新标识中断状态 */ while (!isOnSyncQueue(node)) Thread.yield(); returnfalse; }