在上一篇中,咱們瞭解了下J.U.C的鎖的獲取與釋放的過程,這個過程主要經過在A.Q.S中維持一個等待隊列來實現,其中咱們也提到了,在A.Q.S中除了一個等待隊列以外,還有一個Condition隊列,在瞭解Condition隊列以前,先來看一下Condition是怎麼回事: node
The synchronizer framework provides a ConditionObject class for use by synchronizers that maintain exclusive synchronization and conform to the Lock interface. Any number of condition objects may be attached to a lock object, providing classic monitor-style await, signal, and signalAll operations, including those with timeouts, along with some inspection and monitoring methods. 框架
上面的這一段內容摘自Doug Lea的AQS論文,從上面這一段話能夠看出,Condition主要是爲了在J.U.C框架中提供和Java傳統的監視器風格的wait,notify和notifyAll方法相似的功能,那麼先來解釋一下這三個方法的做用: less
那麼Condition是如何實現wait,notify和notifyAll方法的功能呢?咱們接下來看: ide
在Condition中,wait,notify和notifyAll方法分別對應了await,signal和signalAll方法,固然Condition也提供了超時的、不可被中斷的await()方法,不過咱們主要仍是看一看await,notify和notifyAll的實現,先看await: 動畫
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
publicfinalvoidawait()throwsInterruptedException {
if(Thread.interrupted())
thrownewInterruptedException();
Node node = addConditionWaiter();
intsavedState = fullyRelease(node);
intinterruptMode =0;
while(!isOnSyncQueue(node)) {
LockSupport.park(this);
if((interruptMode = checkInterruptWhileWaiting(node)) !=0)
break;
}
if(acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if(node.nextWaiter !=null)
unlinkCancelledWaiters();
if(interruptMode !=0)
reportInterruptAfterWait(interruptMode);
}
|
整個await的過程以下: ui
能夠看到,這個await的操做過程和Object.wait()方法是同樣,只不過await()採用了Condition隊列的方式實現了Object.wait()的功能。 this
在瞭解了await方法的實現之後,signal和signalAll方法的實現就相對簡單了,先看看signal方法: spa
1
2
3
4
5
6
7
|
publicfinalvoidsignal() {
if(!isHeldExclusively())
thrownewIllegalMonitorStateException();
Node first = firstWaiter;
if(first !=null)
doSignal(first);
}
|
這裏先判斷當前線程是否持有鎖,若是沒有持有,則拋出異常,而後判斷整個condition隊列是否爲空,不爲空則調用doSignal方法來喚醒線程,看看doSignal方法都幹了一些什麼: 線程
1
2
3
4
5
6
7
8
|
privatevoiddoSignal(Node first) {
do{
if( (firstWaiter = first.nextWaiter) ==null)
lastWaiter =null;
first.nextWaiter =null;
}while(!transferForSignal(first) &&
(first = firstWaiter) !=null);
}
|
這個while循環的做用就是將firstWaiter往Condition隊列的後面移一位,而且喚醒first,看看while循環中tranferForSignal: orm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
finalbooleantransferForSignal(Node node) {
/*
* If cannot change waitStatus, the node has been cancelled.
*/
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
/*
* 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).
*/
Node p = enq(node);
intc = p.waitStatus;
if(c >0|| !compareAndSetWaitStatus(p, c, Node.SIGNAL))
LockSupport.unpark(node.thread);
returntrue;
}
|
這段代碼的做用就是修改Node的waitStatus爲0,而後將Node插入到等待隊列中,而且喚醒Node。
signalAll和signal方法相似,主要的不一樣在於它不是調用doSignal方法,而是調用doSignalAll方法:
1
2
3
4
5
6
7
8
9
|
privatevoiddoSignalAll(Node first) {
lastWaiter = firstWaiter =null;
do{
Node next = first.nextWaiter;
first.nextWaiter =null;
transferForSignal(first);
first = next;
}while(first !=null);
}
|
這個方法就至關於把Condition隊列中的全部Node所有取出插入到等待隊列中去。
在瞭解了await(),signal()和signalAll方法的實現之後,咱們再來經過一副gif動畫來看一看這一個總體的過程: