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

JDK 1.8 LockSupport 源碼深度剖析:park/unpark 底層原理與 wait/notify 關鍵差異

     編輯:Java 程式設計入門

LockSupport 定位

Java 同步器框架(AQS、ReentrantLock 等)的基礎阻塞原語,純靜態方法工具類,核心依賴 sun.misc.Unsafe 原生操作。

核心欄位與初始化

private static final Unsafe UNSAFE = Unsafe.getUnsafe();
// Thread 實例欄位在記憶體中的偏移量,供 Unsafe 直接讀寫
private static final long parkBlockerOffset = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("parkBlocker"));
private static final long SEED = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomSeed"));
private static final long PROBE = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomProbe"));
private static final long SECONDARY = UNSAFE.objectFieldOffset(Thread.class.getDeclaredField("threadLocalRandomSecondarySeed"));
  • parkBlocker:記錄阻塞原因物件,便診斷工具監控
  • 其餘三欄位:支援 ThreadLocalRandom 線程本地隨機數生成器

核心方法解析

park() - 阻塞當前線程

public static void park() {
    UNSAFE.park(false, 0L); // 無限期等待許可
}

public static void park(Object blocker) {
    Thread t = Thread.currentThread();
    setBlocker(t, blocker);      // 設置阻塞原因
    UNSAFE.park(false, 0L);      // 進入阻塞
    setBlocker(t, null);         // 恢復運行後清除
}

private static void setBlocker(Thread t, Object arg) {
    UNSAFE.putObject(t, parkBlockerOffset, arg);
}

為何雙次 setBlocker? 阻塞前記錄原因,被 unpark 喚醒後清除,避免殘留舊資訊誤導診斷。

parkNanos / parkUntil - 限時阻塞

public static void parkNanos(Object blocker, long nanos) { // 相對時間(奈秒)
    if (nanos > 0) {
        setBlocker(t, blocker);
        UNSAFE.park(false, nanos);
        setBlocker(t, null);
    }
}

public static void parkUntil(Object blocker, long deadline) { // 絕對時間(毫秒時間戳)
    setBlocker(t, blocker);
    UNSAFE.park(true, deadline);
    setBlocker(t, null);
}

unpark(Thread) - 釋放許可

public static void unpark(Thread thread) {
    if (thread != null) UNSAFE.unpark(thread);
}
  • 為指定線程發放「許可」
  • 線程在 park 中 → 立即恢復運行
  • 線程未在 park → 下次 park 不阻塞直接通過(許可不疊加,最多 1 個)

Unsafe 原生語義

native void park(boolean isAbsolute, long time);  // isAbsolute=true 時 time 為絕對截止時間
native void unpark(Thread thread);

三種喚醒條件:unpark、線程中斷、時間到期(或虛假喚醒)。

實戰對比:LockSupport vs wait/notify

場景:兩線程同步(主線程等待子線程完成)

wait/notify 版本 - 順序強耦合

synchronized (obj) {
    obj.wait();  // 必須先 wait
}
// 子線程
synchronized (obj) {
    obj.notify(); // 必須後 notify,反序則主線程永久阻塞
}

park/unpark 版本 - 順序無關

// 主線程
LockSupport.park("Demo"); // 可先 park

// 子線程
LockSupport.unpark(mainThread); // 後 unpark 也能正確喚醒

關鍵優勢:unpark 建立「許可」狀態,不依賴執行順序,彈性極高。

中斷響應測試

// 主線程 park 中
LockSupport.park();
// 子線程
mainThread.interrupt(); // 相當於 unpark,主線程恢復運行

中斷同樣能喚醒 park,但不會拋出 InterruptedException,需自行檢查 Thread.interrupted()。

總結

  • LockSupport 是構建鎖、信號量、屏障等同步元件的基石
  • park = 等待許可,unpark = 發放許可
  • 比 wait/notify 更靈活:無須同步塊、無順序依賴、支援阻塞原因診斷
  • AQS、ReentrantLock、CountDownLatch 等高階組件底層皆委派 LockSupport
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved