Condition接口見Condition接口詳解
ConditionObject定義
- 定義為AQS的public內(nèi)部類悬蔽,方便獲取FIFO同步隊列踏烙,并將此類對象對外暴露.
- ** 條件等待隊列是單向隊列**:需要注意的是和AQS的FIFO的head相比椅棺,此首節(jié)點并沒有head節(jié)點信息傳播通知的功能比原,而且首節(jié)點是第一個阻塞的線程節(jié)點。
1- await方法
- await
步驟:
- 將節(jié)點加入條件等待隊列中
- 釋放同步狀態(tài)
- 死循環(huán)阻塞婶熬,直到被通知或者被中斷:1) 當(dāng)被通知喚醒時還得判斷一下當(dāng)前節(jié)點是否已經(jīng)轉(zhuǎn)移到AQS同步隊列當(dāng)中(其實主動通知的線程會確保其后繼等待節(jié)點轉(zhuǎn)移到同步隊列中剑勾,所以被通知后在下一次循環(huán)條件為false埃撵,繼續(xù)后續(xù)流程);2) 當(dāng)被中斷喚醒時需要確保節(jié)點被轉(zhuǎn)移到同步隊列中虽另,然后根據(jù)中斷發(fā)生在被通知前后位置設(shè)置中斷模式暂刘,并跳出循環(huán)。
- 關(guān)于中斷模式: 1) 當(dāng)在被通知前被中斷則將中斷模式設(shè)置為THROW_IE捂刺; 2) 當(dāng)在被通知后則將中斷模式設(shè)置為REINTERRUPT(因為acquireQueued不會響應(yīng)中斷)谣拣。
- 死循環(huán)獲取同步狀態(tài),并在同步狀態(tài)獲取成功或者取消獲取時設(shè)置中斷模式:如果在被通知之后獲取鎖過程中發(fā)生中斷則將中斷模式設(shè)置為REINTERRUPT族展。
- 刪除取消的后繼等待節(jié)點森缠。
- 根據(jù)中斷模式拋出異常。
注意:被中斷的線程跳出while循環(huán)后仪缸,會調(diào)用acquireQueued方法自旋獲取鎖贵涵,嘗試獲取同步狀態(tài),而不是立即響應(yīng)中斷拋出中斷異常恰画。在最后根據(jù)中斷模式來決定是否拋出異常宾茂。
- addConditionWaiter
調(diào)用await方法釋放鎖并將線程添加到條件等待隊列中并沒有采用死循環(huán)CAS設(shè)置(對比AQS.enq方法),因為Condition對象只能用于獨占模式拴还,而且在調(diào)用await之前會顯示的獲取獨占鎖跨晴,否則會拋出非法監(jiān)視器狀態(tài)異常。
- fullyRelease
等待的線程自沧,是已經(jīng)獲取到鎖的線程坟奥,當(dāng)線程調(diào)用wait方法時會首先釋放鎖,然后再阻塞自自身拇厢。** 當(dāng)沒有顯示的獲取鎖爱谁,直接調(diào)用await方法,會在這個方法拋出非法監(jiān)視器異常的錯誤 **孝偎。
- isOnSyncQueue
- 第一個if語句:不管是因為中斷還是被通知(詳見transferAfterCancelledWait()和transferForSignal()方法)轉(zhuǎn)移到AQS同步隊列的節(jié)點狀態(tài)為都會設(shè)置為初始狀態(tài)(值為0)访敌,所以當(dāng)發(fā)現(xiàn)
node.waitStatus == Node.CONDITION
為真時,說明還沒有轉(zhuǎn)移到同步隊列中衣盾,返回false寺旺,在下一次while循環(huán)中判斷是否轉(zhuǎn)移成功。 - 第二個if語句進行判斷势决,當(dāng)節(jié)點是AQS同步隊列的中間節(jié)點時(在同步隊列中含有next節(jié)點)則返回true阻塑;
- 當(dāng)節(jié)點為尾節(jié)點時,在return語句里 果复,從后到前遍歷陈莽,如果存在則返回true,否則返回false。
- findNodeFromTail
- checkInterruptWhileWaiting
當(dāng)發(fā)生中斷走搁,則確保中斷的線程加入同步隊列中独柑,并根據(jù)transferAfterCancelledWait的返回值來設(shè)置中斷模式。
- reportInterruptAfterWait
如果中斷模式為THROW_IE則拋出中斷異常
- unlinkCancelledWaiters
- transferAfterCancelledWait
確保取消的節(jié)點加入同步隊列中私植,如果中斷或者超時發(fā)生在通知之前則將狀態(tài)設(shè)置為0并返回true忌栅,否則返回false。
2- awaitUninterruptibly方法
3- awaitNanos方法
4- awaitUntil方法
5- await(long time, TimeUnit unit)方法
6- signal方法
每一個被通知的節(jié)點狀態(tài)由CONDITION設(shè)置為0曲稼,并隨后確保被通知的節(jié)點在加入到同步隊列后能被前繼節(jié)點通知到(SIGNAL或者直接喚醒)索绪。
7- signalAll方法
查詢操作
8- isOwnedBy方法
9- hasWaiters方法
10- getWaitQueueLength方法
11- getWaitingThreads方法
總結(jié)
- 每一個創(chuàng)建的ConditionObject都維持這各自的一個單向的等待隊列,但是每個ConditionObject都共享一個AQS的FIFO同步隊列贫悄,當(dāng)調(diào)用await方法時釋放鎖并進入阻塞狀態(tài)者春,調(diào)用signal方法將條件等待隊列中的首節(jié)點線程移動到AQS同步隊列中并將其前繼節(jié)點設(shè)置為SIGNAL或者直接喚醒線程使得被通知的線程能去獲取鎖。
- 調(diào)用await方法釋放鎖并將線程添加到條件等待隊列中并沒有采用死循環(huán)CAS設(shè)置(參考AQS.enq方法)清女,因為Condition對象只能用于獨占模式钱烟,而且在調(diào)用await之前會顯示的獲取獨占鎖,否則會拋出非法監(jiān)視器狀態(tài)異常嫡丙。
- 調(diào)用signal方法將轉(zhuǎn)移等待節(jié)點拴袭,也不需要CAS來保證,因為signal會確保調(diào)用者caller是獲取獨占鎖的線程(通過isHeldExclusively方法來判斷曙博,如果為false會拋出非法監(jiān)視器狀態(tài)的異常)拥刻。