AQS的ConditionObject源碼詳解

Condition接口見Condition接口詳解

ConditionObject定義
  1. 定義為AQS的public內(nèi)部類,方便獲取FIFO同步隊列,并將此類對象對外暴露.
  2. ** 條件等待隊列是單向隊列**:需要注意的是和AQS的FIFO的head相比,此首節(jié)點(diǎn)并沒有head節(jié)點(diǎn)信息傳播通知的功能,而且首節(jié)點(diǎn)是第一個阻塞的線程節(jié)點(diǎn)。
1- await方法
  1. await

步驟:

  1. 將節(jié)點(diǎn)加入條件等待隊列中
  2. 釋放同步狀態(tài)
  3. 死循環(huán)阻塞,直到被通知或者被中斷:1) 當(dāng)被通知喚醒時還得判斷一下當(dāng)前節(jié)點(diǎn)是否已經(jīng)轉(zhuǎn)移到AQS同步隊列當(dāng)中(其實主動通知的線程會確保其后繼等待節(jié)點(diǎn)轉(zhuǎn)移到同步隊列中,所以被通知后在下一次循環(huán)條件為false,繼續(xù)后續(xù)流程);2) 當(dāng)被中斷喚醒時需要確保節(jié)點(diǎn)被轉(zhuǎn)移到同步隊列中,然后根據(jù)中斷發(fā)生在被通知前后位置設(shè)置中斷模式,并跳出循環(huán)。
  4. 關(guān)于中斷模式: 1) 當(dāng)在被通知前被中斷則將中斷模式設(shè)置為THROW_IE; 2) 當(dāng)在被通知后則將中斷模式設(shè)置為REINTERRUPT(因為acquireQueued不會響應(yīng)中斷)。
  5. 死循環(huán)獲取同步狀態(tài),并在同步狀態(tài)獲取成功或者取消獲取時設(shè)置中斷模式:如果在被通知之后獲取鎖過程中發(fā)生中斷則將中斷模式設(shè)置為REINTERRUPT。
  6. 刪除取消的后繼等待節(jié)點(diǎn)。
  7. 根據(jù)中斷模式拋出異常。

注意:被中斷的線程跳出while循環(huán)后,會調(diào)用acquireQueued方法自旋獲取鎖,嘗試獲取同步狀態(tài),而不是立即響應(yīng)中斷拋出中斷異常。在最后根據(jù)中斷模式來決定是否拋出異常。

  1. addConditionWaiter

調(diào)用await方法釋放鎖并將線程添加到條件等待隊列中并沒有采用死循環(huán)CAS設(shè)置(對比AQS.enq方法),因為Condition對象只能用于獨(dú)占模式,而且在調(diào)用await之前會顯示的獲取獨(dú)占鎖,否則會拋出非法監(jiān)視器狀態(tài)異常。

  1. fullyRelease

等待的線程,是已經(jīng)獲取到鎖的線程,當(dāng)線程調(diào)用wait方法時會首先釋放鎖,然后再阻塞自自身。** 當(dāng)沒有顯示的獲取鎖,直接調(diào)用await方法,會在這個方法拋出非法監(jiān)視器異常的錯誤 **。

  1. isOnSyncQueue
  • 第一個if語句:不管是因為中斷還是被通知(詳見transferAfterCancelledWait()和transferForSignal()方法)轉(zhuǎn)移到AQS同步隊列的節(jié)點(diǎn)狀態(tài)為都會設(shè)置為初始狀態(tài)(值為0),所以當(dāng)發(fā)現(xiàn)node.waitStatus == Node.CONDITION為真時,說明還沒有轉(zhuǎn)移到同步隊列中,返回false,在下一次while循環(huán)中判斷是否轉(zhuǎn)移成功。
  • 第二個if語句進(jìn)行判斷,當(dāng)節(jié)點(diǎn)是AQS同步隊列的中間節(jié)點(diǎn)時(在同步隊列中含有next節(jié)點(diǎn))則返回true;
  • 當(dāng)節(jié)點(diǎn)為尾節(jié)點(diǎn)時,在return語句里 ,從后到前遍歷,如果存在則返回true,否則返回false。
  1. findNodeFromTail
  1. checkInterruptWhileWaiting

當(dāng)發(fā)生中斷,則確保中斷的線程加入同步隊列中,并根據(jù)transferAfterCancelledWait的返回值來設(shè)置中斷模式。

  1. reportInterruptAfterWait

如果中斷模式為THROW_IE則拋出中斷異常

  1. unlinkCancelledWaiters
  1. transferAfterCancelledWait

確保取消的節(jié)點(diǎn)加入同步隊列中,如果中斷或者超時發(fā)生在通知之前則將狀態(tài)設(shè)置為0并返回true,否則返回false。

2- awaitUninterruptibly方法
3- awaitNanos方法
4- awaitUntil方法
5- await(long time, TimeUnit unit)方法
6- signal方法




每一個被通知的節(jié)點(diǎn)狀態(tài)由CONDITION設(shè)置為0,并隨后確保被通知的節(jié)點(diǎn)在加入到同步隊列后能被前繼節(jié)點(diǎn)通知到(SIGNAL或者直接喚醒)。

7- signalAll方法

查詢操作

8- isOwnedBy方法
9- hasWaiters方法
10- getWaitQueueLength方法
11- getWaitingThreads方法
總結(jié)
  1. 每一個創(chuàng)建的ConditionObject都維持這各自的一個單向的等待隊列,但是每個ConditionObject都共享一個AQS的FIFO同步隊列,當(dāng)調(diào)用await方法時釋放鎖并進(jìn)入阻塞狀態(tài),調(diào)用signal方法將條件等待隊列中的首節(jié)點(diǎn)線程移動到AQS同步隊列中并將其前繼節(jié)點(diǎn)設(shè)置為SIGNAL或者直接喚醒線程使得被通知的線程能去獲取鎖。
  2. 調(diào)用await方法釋放鎖并將線程添加到條件等待隊列中并沒有采用死循環(huán)CAS設(shè)置(參考AQS.enq方法),因為Condition對象只能用于獨(dú)占模式,而且在調(diào)用await之前會顯示的獲取獨(dú)占鎖,否則會拋出非法監(jiān)視器狀態(tài)異常。
  3. 調(diào)用signal方法將轉(zhuǎn)移等待節(jié)點(diǎn),也不需要CAS來保證,因為signal會確保調(diào)用者caller是獲取獨(dú)占鎖的線程(通過isHeldExclusively方法來判斷,如果為false會拋出非法監(jiān)視器狀態(tài)的異常)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容