Condition在ReentrantLock中,其實是建立AQS的ConditionObject對象,主要的成員變量有Node類型的firstWaiter和lastWaiter,做爲頭節點和尾節點,是單向鏈表。當調用await時,加入隊列,signal時,加入到AQS的阻塞隊列。node
把節點移到Condition隊列後掛起less
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter();//添加一個節點成爲尾節點 int savedState = fullyRelease(node);//釋放全部持有的鎖 int interruptMode = 0; while (!isOnSyncQueue(node)) {//要麼中斷,要麼進入阻塞隊列,退出while循環 LockSupport.park(this);//掛起 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//中斷過,就跳出循環 break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE)//是否被中斷。acquireQueued以前講過 interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled若是尾節點不爲空 unlinkCancelledWaiters();//將不是CONDITION狀態的移除出去 if (interruptMode != 0) reportInterruptAfterWait(interruptMode);//從新中斷 }
addConditionWaiter,若是尾節點不在隊列裏,先移除已取消的節點,添加一個節點成爲尾節點ui
private Node addConditionWaiter() { Node t = lastWaiter; // If lastWaiter is cancelled, clean out.若是尾節點不爲空,可是狀態不是CONDITION,說明已取消,不想在Condition的隊列裏,就移除 if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters();//將不是CONDITION狀態的移除出去 t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION);//建立狀態是CONDITION的節點 if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node;//加入到尾節點 return node; }
fullyRelease方法this
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)//若是釋放失敗,狀態就變成CANCELLED,而不是CONDITION,因此會在addConditionWaiter方法中被移除 node.waitStatus = Node.CANCELLED; } }
isOnSyncQueue方法spa
final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null)//若是狀態是CONDITION或者前置節點爲空,說明還在Condition隊列裏 return false; if (node.next != null) // If has successor, it must be on queue若是有後續節點了,確定是在阻塞隊列裏 return true; /* * 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. */ return findNodeFromTail(node);//從阻塞隊列的尾節點遍歷,若是找到當前node,說明在阻塞隊列裏返回true }
checkInterruptWhileWaiting方法,喚醒前已經中斷,返回THROW_IE,喚醒後中斷,返回REINTERRUPT,沒有中斷,返回0code
private int checkInterruptWhileWaiting(Node node) { return Thread.interrupted() ? (transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) : 0; } final boolean transferAfterCancelledWait(Node node) { //若是cas操做成功,且預期值是CONDITION狀態,說明在喚醒前就中斷了,並加入阻塞隊列 if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; } while (!isOnSyncQueue(node))//一直到阻塞隊列裏,在喚醒後才中斷 Thread.yield(); return false; }
喚醒Condition隊列的節點對象
public final void signal() { if (!isHeldExclusively())//非獨佔拋異常 throw new IllegalMonitorStateException(); Node first = firstWaiter;//獲取頭結點 if (first != null) doSignal(first);//喚醒頭節點 } //若是頭結點已經取消,就繼續往下個節點尋找 private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null)//把下一個節點移到頭結點 lastWaiter = null; first.nextWaiter = null;//help gc } while (!transferForSignal(first) && (first = firstWaiter) != null); } final boolean transferForSignal(Node node) { /* * 若是cas操做沒成功,說明已經取消了,就繼續下一個節點 */ if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* * 沒有取消,就加入阻塞隊列,這個方法在aqs講過了 * */ Node p = enq(node); int ws = p.waitStatus;//前置節點的狀態 //大於0,說明前置節點已取消,就輪到當前節點,能夠喚醒 //小於等於哦,把前置節點的狀態設置爲-1,若是失敗了,喚醒 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread);//喚醒 return true; }