AbstractQueuedSynchronizer ConditionObject解析
分析過程
// condition佇列第一個節點
private transient Node firstWaiter;
// condition佇列最後一個節點
private transient Node lastWaiter;
// 重新中斷退出等待
private static final int REINTERRUPT = 1;
// 丟擲中斷異常退出等待
private static final int THROW_IE = -1;
首先來看 ConditionObject. await()
等待方法
// AbstractQueuedSynchronizer.ConditionObject
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)) {
LockSupport.park(this); // 阻塞執行緒
// 等待後檢查中斷
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 使用獨佔不可中斷模式獲取鎖 且 中斷模式不是THROW_IE 則設定中斷模式為REINTERRUPT
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters(); //【斷開condition佇列已取消的等待節點】
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode); // 根據中斷模式進行相應處理
}
為等待佇列新增新節點
// AbstractQueuedSynchronizer.ConditionObject
private Node addConditionWaiter() {
Node t = lastWaiter;
// 如果最後一個等待是取消狀態則移除
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters(); // 【斷開取消狀態的等待結點】
t = lastWaiter;
}
// 建立狀態為CONDITION的新節點
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node; // condition佇列為空,新增為第一個節點
else
t.nextWaiter = node; // 將原有最後一個等待結點的前一個節點指向當前節點
lastWaiter = node; // 將當前節點設定為condition佇列的最後一個節點
return node;
}
斷開取消狀態的等待結點
private void unlinkCancelledWaiters() {
Node t = firstWaiter; // 第一個等待節點
Node trail = null; // 儲存狀態為CONDITION的遺留節點
// 從頭開始迴圈condition佇列
while (t != null) {
Node next = t.nextWaiter;
// 如果等待狀態為CONDITION 則將下一個節點設定為null,斷開關聯
if (t.waitStatus != Node.CONDITION) {
t.nextWaiter = null;
// 如果沒有遺留節點,則將下一個節點設定為第一個節點
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next; // 存在遺留節點,將下一個節點設定為遺留節點的下一個節點
// 遍歷至尾部,將condition佇列最後一個節點指向遺留節點
if (next == null)
lastWaiter = trail;
}
else
trail = t; // 記錄狀態為CONDITION的遺留節點
t = next; // 迴圈下一個節點
}
}
為當前狀態值呼叫釋放方法,返回儲存狀態,在失敗時取消節點並丟擲異常
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)
node.waitStatus = Node.CANCELLED;
}
}
判斷等待佇列上的節點是否正在同步佇列上等待獲取鎖
final boolean isOnSyncQueue(Node node) {
// 如果節點等待狀態為CONDITION 或 節點的前驅節點為空,則返回false
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 節點存在後繼節點,說明還在同步佇列上等待獲取鎖
if (node.next != null) // If has successor, it must be on queue
return true;
return findNodeFromTail(node); // 從佇列尾部開始查詢當前節點是否處於同步佇列中
}
ConditionObject.signal()
喚醒方法
// AbstractQueuedSynchronizer.ConditionObject
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; // 將頭節點的下一節點設定為空
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
轉換條件佇列節點至同步佇列
final boolean transferForSignal(Node node) {
// CAS設定等待狀態,設定失敗說明節點已經被取消
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node); // 將節點新增至同步佇列
int ws = p.waitStatus;
// 如果節點被取消 或 CAS設定等待狀態為SIGNAL失敗
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread); // 喚醒節點所屬執行緒
return true;
}
主要的等待喚醒方法分析完成。
參考資料
併發程式設計的藝術
相關文章
- AbstractQueuedSynchronizer原始碼解析原始碼
- AbstractQueuedSynchronizer(AQS)原始碼解析AQS原始碼
- AbstractQueuedSynchronizer部分原始碼解析原始碼
- AbstractQueuedSynchronizer原理剖析
- AbstractQueuedSynchronizer筆記筆記
- AbstractQueuedSynchronizer(AQS)深入剖析AQS
- AbstractQueuedSynchronizer原始碼分析原始碼
- 【JDK1.8】JUC——AbstractQueuedSynchronizerJDK
- 深入理解AbstractQueuedSynchronizer(AQS)AQS
- 同步器AbstractQueuedSynchronizer淺析
- 初識Lock與AbstractQueuedSynchronizer(AQS)AQS
- java併發神器 AQS(AbstractQueuedSynchronizer)JavaAQS
- AbstractQueuedSynchronizer 佇列同步器(AQS)佇列AQS
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(3)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(2)JDK原始碼
- 【JDK】JDK原始碼分析-AbstractQueuedSynchronizer(1)JDK原始碼
- Java併發——AbstractQueuedSynchronizer(AQS)同步器JavaAQS
- 從ReentrantLock看AQS (AbstractQueuedSynchronizer) 執行流程ReentrantLockAQS
- 原始碼分析:同步基礎框架——AbstractQueuedSynchronizer(AQS)原始碼框架AQS
- 怎麼利用AbstractQueuedSynchronizer實現自定義同步元件?元件
- Java 併發程式設計(七) -- AbstractQueuedSynchronizer 原始碼分析Java程式設計原始碼
- Java 併發程式設計(八) -- AbstractQueuedSynchronizer中的NodeJava程式設計
- 聊聊JUC包下的底層支撐類-AbstractQueuedSynchronizer(AQS)AQS
- Java 中佇列同步器 AQS(AbstractQueuedSynchronizer)實現原理Java佇列AQS
- AbstractQueuedSynchronizer(AQS)抽絲剝繭深入瞭解JUC框架原理AQS框架
- 全網最詳細的AbstractQueuedSynchronizer(AQS)原始碼剖析(一)AQS基礎AQS原始碼
- 全網最詳細的AbstractQueuedSynchronizer(AQS)原始碼剖析(三)條件變數AQS原始碼變數
- 硬核乾貨:5W字17張高清圖理解同步器框架AbstractQueuedSynchronizer框架
- 全網最詳細的AbstractQueuedSynchronizer(AQS)原始碼剖析(二)資源的獲取和釋放AQS原始碼
- 解析-解析器
- ORACLE SQL解析之硬解析和軟解析OracleSQL
- 解析-HTML 解析器HTML
- Nginx(六):配置解析之location解析Nginx
- XML 檔案解析實踐 (DOM 解析)XML
- dom解析和sax解析的區別
- 雲解析DNS如何實現智慧解析?DNS
- 什麼是智慧DNS雲解析?雲解析如何實現智慧解析效果?DNS
- 雲解析VS傳統解析,雲解析到底有哪些實際用途?