LockSupport 是 JUC(java.util.concurrent)包中最基礎的線程阻塞/喚醒原語。AQS、ReentrantLock、CountDownLatch、FutureTask 等高級組件底層均依賴它。本文深度剖析其核心 API、許可證機制、三大核心場景、源碼實現原理及與 Object.wait/notify 的本質區別。
| 方法 | 作用 | 關鍵特性 |
|---|---|---|
park() | 阻塞當前線程,等待許可證 | 無參,可攜帶 blocker 對象用於診斷 |
park(Object blocker) | 阻塞並記錄阻塞器 | LockSupport.getBlocker(thread) 可獲取,排查死鎖利器 |
parkNanos(long nanos) | 限時阻塞(相對時間) | 超時自動返回,不拋異常 |
parkUntil(long deadline) | 限時阻塞(絕對時間) | 截止時間 = System.nanoTime() + timeout |
unpark(Thread thread) | 發放許可證,喚醒目標線程 | 可提前發放,許可證不累積(最多 1 個) |
getBlocker(Thread thread) | 獲取線程阻塞時傳入的 blocker | 需線程調用 park(blocker) 才生效 |
unpark:許可證 = 1(若已為 1 則保持 1,不疊加)。park:若許可證 = 1 → 消耗許可證(歸 0)立即返回;若許可證 = 0 → 線程阻塞,等待許可證。unpark 可在 park 之前調用(提前發放),線程隨後調用 park 直接通過不阻塞。這解決了 wait/notify 的「通知丟失」痛點。public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
System.out.println("Worker: 開始工作,等待許可...");
LockSupport.park(); // 阻塞
System.out.println("Worker: 獲得許可,繼續執行");
});
worker.start();
Thread.sleep(1000); // 模擬主線程準備
System.out.println("Main: 發放許可");
LockSupport.unpark(worker); // 喚醒
}
/* 輸出:
Worker: 開始工作,等待許可...
Main: 發放許可
Worker: 獲得許可,繼續執行
*/
public static void main(String[] args) {
Thread worker = new Thread(() -> {
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
System.out.println("Worker: 準備就緒,檢查許可...");
LockSupport.park(); // 直接通過,不阻塞!
System.out.println("Worker: 繼續執行");
});
worker.start();
System.out.println("Main: 提前發放許可");
LockSupport.unpark(worker); // 許可證 = 1
}
/* 輸出:
Main: 提前發放許可
Worker: 準備就緒,檢查許可...
Worker: 繼續執行
*/
public static void main(String[] args) throws InterruptedException {
Thread worker = new Thread(() -> {
String context = "任務ID: 10086, 優先級: HIGH";
System.out.println("Worker: 阻塞,上下文: " + context);
LockSupport.park(context); // 傳遞 blocker
System.out.println("Worker: 喚醒");
});
worker.start();
Thread.sleep(500);
System.out.println("Main: 檢查阻塞器 -> " + LockSupport.getBlocker(worker)); // 獲取上下文
LockSupport.unpark(worker);
}
/* 輸出:
Worker: 阻塞,上下文: 任務ID: 10086, 優先級: HIGH
Main: 檢查阻塞器 -> 任務ID: 10086, 優先級: HIGH
Worker: 喚醒
*/
// LockSupport 靜態內部類
static class ParkEvent {
volatile int state; // 0=無許可, 1=有許可
// ... 平台相關 mutex/cond
}
// 關鍵 UNSAFE 實例
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
public static void unpark(Thread thread) {
if (thread != null) {
ParkEvent ev = getParkEvent(thread); // 獲取/創建線程關聯的 ParkEvent
ev.state = 1; // 設置許可證 = 1
ev.release(); // 平台相關:pthread_cond_signal / SetEvent / unpark
}
}
public static void park() {
ParkEvent ev = getParkEvent(Thread.currentThread());
if (ev.state == 1) { // 快速路徑:有許可
ev.state = 0; // 消耗許可
return;
}
// 慢速路徑:無許可,進入阻塞
ev.park(); // 平台相關:pthread_cond_wait / WaitForSingleObject / park
ev.state = 0; // 被喚醒後消耗許可
}
| 維度 | LockSupport.park/unpark | Object.wait/notify |
|---|---|---|
| 鎖依賴 | 無需鎖 | 必須持有對象監視器鎖 |
| 通知丟失 | 不丟失(許可證機制) | 易丟失(notify 前 wait 未執行) |
| 喚醒目標 | 精確指定線程 | 隨機喚醒一個/全部 |
| 攜帶上下文 | 支持 blocker 診斷 | 不支持 |
| 超時控制 | 納秒/截止時間精確 | 毫秒精度 |
| 中斷響應 | 阻塞中可中斷(Thread.interrupt) | 可中斷,拋 InterruptedException |
| 適用層級 | 底層原語,構建鎖/同步器 | 高層協作,業務代碼慎用 |
public void awaitWithInterrupt() throws InterruptedException {
while (!conditionMet) { // 防虛假喚醒/中斷喚醒
LockSupport.park(this);
if (Thread.interrupted()) { // 檢查中斷狀態,不拋異常
throw new InterruptedException();
}
}
}
// 或使用 parkNanos/parkUntil 實現超時等待
LockSupport 以許可證機制解決了傳統 wait/notify 的「通知丟失、隨機喚醒、鎖綁定」三大痛點,成為 JUC 同步體系的基石原語。掌握其無鎖阻塞、提前發放、攜帶上下文、精確喚醒特性,不僅能讀懂 AQS/ReentrantLock 源碼,更能在需要精細線程控制的場景(如自定義同步器、線程池任務協調、無鎖算法輔助)中靈活運用,寫出更底層、更高效的並發代碼。