AQS中提供了一個(gè)實(shí)現(xiàn)Condition接口的內(nèi)部類ConditionObject哗伯,其內(nèi)部也維護(hù)了一個(gè)隊(duì)列,首尾分別為firstWaiter,lastWaiter负蠕。當(dāng)然九巡,condition中最重要的兩類方法就是await和signal。
首先室琢,我們來看await方法乾闰,在接口注釋中我們知道該方法會(huì)導(dǎo)致當(dāng)前線程等待直到被喚醒或者被中斷。與該condition關(guān)聯(lián)的鎖會(huì)被自動(dòng)釋放并阻塞當(dāng)前線程盈滴。在這個(gè)方法返回之前必須重新?lián)碛墟i涯肩。這里,我們先來看awaitUninterruptibly方法巢钓,這個(gè)方法是不響應(yīng)中斷的病苗。
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
該方法新建了一個(gè)Node鏈接到lastWaiter之后。然后調(diào)用fullyRelease方法症汹,該方法內(nèi)部調(diào)用了release方法解鎖了同步隊(duì)列中頭結(jié)點(diǎn)的一個(gè)后繼節(jié)點(diǎn)硫朦,可參考AQS(3)。然后判斷當(dāng)前節(jié)點(diǎn)是否在同步隊(duì)列中背镇,如果不在咬展,那么阻塞當(dāng)前線程。直到while條件為true芽世,此時(shí)當(dāng)前線程處于等待隊(duì)列挚赊,并且需要再次acquire。
然后我們來看signal方法济瓢,先貼代碼
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
}
while (!transferForSignal(first) && (first = firstWaiter) != null);
}
這個(gè)方法從頭節(jié)點(diǎn)開始荠割,然后調(diào)用了transferForSignal方法,將頭結(jié)點(diǎn)從條件隊(duì)列移到了等待隊(duì)列旺矾。此時(shí)會(huì)將ws用CAS置為0蔑鹦。然后將節(jié)點(diǎn)用enq方法入隊(duì)并返回其前驅(qū)結(jié)點(diǎn),需要將前驅(qū)節(jié)點(diǎn)用CAS設(shè)置為SIGNAL表示其后繼需要被解鎖箕宙。
我們將兩個(gè)方法結(jié)合起來看嚎朽,首先一個(gè)線程調(diào)用await,那么會(huì)新建一個(gè)節(jié)點(diǎn)加入條件隊(duì)列柬帕,然后它會(huì)釋放持有的鎖哟忍。這時(shí)它仍然在條件隊(duì)列狡门,因此在第一次循環(huán)中會(huì)被阻塞。while循環(huán)保證了中斷或者假喚醒不會(huì)導(dǎo)致出錯(cuò)锅很。這時(shí)其馏,另一線程調(diào)用了signal操作,它從條件隊(duì)列拿出第一個(gè)節(jié)點(diǎn)爆安,把它加入了同步隊(duì)列叛复,并將其前驅(qū)標(biāo)記為SINGNAL指示需要解鎖該節(jié)點(diǎn)。(這個(gè)時(shí)候仍然沒有被喚醒)扔仓,我們知道在signal的時(shí)候仍然需要持有鎖褐奥,當(dāng)這個(gè)線程在釋放鎖的時(shí)候,會(huì)在release方法中解鎖一個(gè)后繼節(jié)點(diǎn)翘簇,此時(shí)同步隊(duì)列只有這個(gè)被阻塞的線程撬码,這時(shí)他就被喚醒了!
除了上述方法外版保,還有signalAll方法耍群,但該方法的區(qū)別就是將所有條件隊(duì)列的節(jié)點(diǎn)都加到了同步隊(duì)列。
而在await系列方法中找筝,await()方法是支持中斷的。該方法會(huì)判斷中斷的時(shí)機(jī)慷吊,如果在signalled之前中斷則拋出異常袖裕,如果在signalled之后中斷則reinterrupt。其他諸如awaitNano,awaitUntil等在主體邏輯上并沒有區(qū)別溉瓶。
到這里急鳄,AQS這部分的簡單介紹就結(jié)束啦!