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 線程本地隨機數生成器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 喚醒後清除,避免殘留舊資訊誤導診斷。
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);
}
public static void unpark(Thread thread) {
if (thread != null) UNSAFE.unpark(thread);
}
park 中 → 立即恢復運行park → 下次 park 不阻塞直接通過(許可不疊加,最多 1 個)native void park(boolean isAbsolute, long time); // isAbsolute=true 時 time 為絕對截止時間
native void unpark(Thread thread);
三種喚醒條件:unpark、線程中斷、時間到期(或虛假喚醒)。
synchronized (obj) {
obj.wait(); // 必須先 wait
}
// 子線程
synchronized (obj) {
obj.notify(); // 必須後 notify,反序則主線程永久阻塞
}
// 主線程
LockSupport.park("Demo"); // 可先 park
// 子線程
LockSupport.unpark(mainThread); // 後 unpark 也能正確喚醒
關鍵優勢:unpark 建立「許可」狀態,不依賴執行順序,彈性極高。
// 主線程 park 中
LockSupport.park();
// 子線程
mainThread.interrupt(); // 相當於 unpark,主線程恢復運行
中斷同樣能喚醒 park,但不會拋出 InterruptedException,需自行檢查 Thread.interrupted()。
LockSupport 是構建鎖、信號量、屏障等同步元件的基石park = 等待許可,unpark = 發放許可wait/notify 更靈活:無須同步塊、無順序依賴、支援阻塞原因診斷LockSupport