首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 多執行緒 LockSupport 核心機制:park/unpark 阻塞喚醒完整解析

     編輯:Java 相關知識

LockSupport 核心定位

java.util.concurrent.locks.LockSupport 是構建鎖與同步器的基礎執行緒阻塞原語,提供 park()(阻塞)與 unpark()(喚醒)方法,解決 Thread.suspend/resume 可能導致的死鎖問題。

許可證機制

每個執行緒關聯一個「許可證」(許可證數量最多 1):

  • unpark():發放許可證(若已有則保持可用狀態)
  • park():消耗許可證(若無則阻塞等待)
  • 許可證不可累積,多次 unpark() 僅保留一個可用狀態

基礎用法示範

基本阻塞與喚醒

public static void main(String[] args) {
    Thread mainThread = Thread.currentThread();
    
    // 先發放許可證,再消耗 → 不阻塞直接通過
    LockSupport.unpark(mainThread);
    LockSupport.park();
    System.out.println("執行緒繼續執行");
}

阻塞等待喚醒

public static void main(String[] args) throws InterruptedException {
    Thread worker = new Thread(() -> {
        System.out.println("工作執行緒開始,準備阻塞...");
        LockSupport.park(); // 等待許可證
        System.out.println("工作執行緒被喚醒,繼續執行");
    });
    worker.start();
    
    Thread.sleep(1000); // 模擬延遲
    System.out.println("主執行緒發放許可證");
    LockSupport.unpark(worker); // 喚醒工作執行緒
}

不可重入特性與死鎖風險

public static void main(String[] args) {
    Thread t = Thread.currentThread();
    LockSupport.unpark(t); // 發放 1 個許可證
    LockSupport.park();    // 消耗 1 個 → 通過
    LockSupport.park();    // 無許可證 → 永久阻塞(死鎖)!
    System.out.println("不會執行到這裡");
}

結論:LockSupport 不可重入,連續呼叫 park() 需對應相同次數的 unpark()。

中斷響應行為

Thread t = new Thread(() -> {
    LockSupport.park();
    System.out.println("阻塞結束,中斷狀態:" + Thread.currentThread().isInterrupted());
});
t.start();
Thread.sleep(100);
t.interrupt(); // 中斷阻塞中的執行緒

行為:park() 會響應中斷,執行緒中斷狀態設為 true,但不拋出 InterruptedException。

進階 API:超時與截止時間

方法說明
parkNanos(long nanos)納秒級超時阻塞
parkUntil(long deadline)截止時間阻塞(毫秒時間戳)
park(Object blocker)關聯阻塞器物件,供診斷工具識別
getBlocker(Thread t)取得執行緒最近阻塞器物件

LockSupport vs Object.wait/notify

特性LockSupportObject.wait/notify
鎖綁定無需 synchronized需持有物件鎖
許可證機制有(不可累積)無
虛假喚醒無可能發生
中斷處理設置中斷旗標拋出 InterruptedException
適用場景構建同步器、AQS 基礎簡單執行緒協作

實際應用:AQS 同步隊列節點阻塞

LockSupport 是 AbstractQueuedSynchronizer (AQS) 核心阻塞機制:

// AQS 內部節點阻塞邏輯簡化
static final class Node {
    Thread thread;
    // ...
}

// 入隊後阻塞等待
LockSupport.park(this); // 關聯自身節點作為 blocker

// 釋放鎖時喚醒後繼節點
LockSupport.unpark(node.next.thread);

blocker 參數讓監控工具(如 jstack)能顯示執行緒阻塞原因,提升可觀測性。

最佳實踐建議

  1. 優先使用高層同步工具(ReentrantLock, CountDownLatch, Semaphore 等)
  2. 自訂同步器時才直接使用 LockSupport
  3. 配合 blocker 參數提升除錯能力
  4. 注意不可重入特性,避免雙重 park 導致死鎖
  5. 中斷處理需檢查 Thread.interrupted() 而非捕獲異常
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved