源码:java.util.concurrent.locks.LockSupport 源码解析

1. TODO


2. 脑图

  1. Xmind

  2. Edraw

  3. Hexo 地址
    👉 http://blog.wangjia.ink/2025/11/13/源码:java.util.concurrent.locks.LockSupport源码解析/


3. 基础部分

3.1. LockSupport 概述

想象这样几个问题:

  1. Object#waitObject#notifysynchronized 是绑定的,它们必须出现在 synchronized 代码块中。也就是说:为了实现一次 “等待” 或 “通知”,线程必须先去竞争到 Monitor 锁。而在高并发场景下,这种对 Monitor 锁的竞争是重量级的
  2. Object#notify() 是唤醒 MonitorWaitSet 中的 “任意” 一个 Thread 实例。而 Object#notifyAll() 是唤醒 MonitorWaitSet 中的所有 Thread 实例,导致 “惊群效应”。它们都没有办法精确唤醒我们指定要唤醒的线程
  3. 除此之外,还有一个经典的竞态条件:如果本地线程 B 调用 Object#notify 先于本地线程 A 调用 Object#wait,那么这个 Object#notify 就永久消失了,本地线程 A 将 ”无限期“ 地等待一个永远不会再来的 Object#notify。而我们往常解决的方法是:在使用 Object#waitObject#notify 前,要先用 while(condition) 循环来检查状态,非常的繁琐

为了解决这一问题,Doug Lea 就封装了 LockSupport,我们在 AQS 中实现的阻塞、唤醒都是基于 LockSupport

LockSupport 体系下,我们可以把每个本地线程想象成一个需要持有 “许可证” 才能继续运行的人。这个许可证不是计数器,不会累加,只有两种状态:10

当我们调用 LockSupport.unpark 唤醒某本地线程时,无论该本地线程是阻塞还是运行,都会为它发放一个 “许可证”

而当我们调用 LockSupport.park 时,本地线程会先检查自己是否持有许可证:

  1. 如果持有许可证
    1. 消耗许可证(许可证从 1 ➔ 0),继续向下执行
  2. 如果未持有许可证
    1. 让本地线程进入阻塞状态,Thread 实例进入 BWTW 状态,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时

[!NOTE] 注意事项

  1. LockSupport.unpark 可以先于 LockSupport.park 执行,而不会 ”条件消失“,这是 Doug Lea 封装它的核心原因

4. 源码部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public class LockSupport {

private LockSupport() {}

// 用于非阻塞设置某本地线程进入阻塞状态,Thread 实例进入 BWTW 状态的原因
//
// 该原因会被设置到 Thread->parkBlocker
private static void setBlocker(Thread t, Object arg) {
U.putReferenceOpaque(t, PARKBLOCKER, arg);
}

// 用于非阻塞设置本地线程进入阻塞状态,Thread 实例进入 BWTW 状态的原因
//
// 该原因会被设置到 Thread->parkBlocker
public static void setCurrentBlocker(Object blocker) {
U.putReferenceOpaque(Thread.currentThread(), PARKBLOCKER, blocker);
}

// 用于非阻塞唤醒某本地线程
public static void unpark(Thread thread) {
if (thread != null)
U.unpark(thread);
}

// 用于让本地线程进入阻塞状态,Thread 实例进入 WAITING 状态,并被投递到使用了 LockSupport 的具体产品维护的数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时,并设置原因
//
// 本地线程进入阻塞状态,Thread 实例进入 WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,不会抛出 InterruptedException 受检异常,但会保留 Thread 实例的中断状态,继续向下执行(正常退出(未发生异常))
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, 0L);
setBlocker(t, null);
}

// 用于让本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态,并被投递到使用了 LockSupport 的具体产品维护的数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时,并设置原因
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,不会抛出 InterruptedException 受检异常,但会保留 Thread 实例的中断状态,继续向下执行(正常退出(未发生异常))
public static void parkNanos(Object blocker, long nanos) {
if (nanos > 0) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(false, nanos);
setBlocker(t, null);
}
}

// 用于让本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态,并被投递到使用了 LockSupport 的具体产品维护的数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时,并设置原因
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,不会抛出 InterruptedException 受检异常,但会保留 Thread 实例的中断状态,继续向下执行(正常退出(未发生异常))
public static void parkUntil(Object blocker, long deadline) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
U.park(true, deadline);
setBlocker(t, null);
}

// 用于非阻塞获取某本地线程进入阻塞状态,Thread 实例进入 BWTW 状态的原因
public static Object getBlocker(Thread t) {
if (t == null)
throw new NullPointerException();
return U.getReferenceOpaque(t, PARKBLOCKER);
}

// 用于让本地线程进入阻塞状态,Thread 实例进入 WAITING 状态,并被投递到使用了 LockSupport 的具体产品维护的数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)
//
// 本地线程进入阻塞状态,Thread 实例进入 WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,不会抛出 InterruptedException 受检异常,但会保留 Thread 实例的中断状态,继续向下执行(正常退出(未发生异常))
public static void park() {
U.park(false, 0L);
}

// 用于让本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态,并被投递到使用了 LockSupport 的具体产品维护的数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,不会抛出 InterruptedException 受检异常,但会保留 Thread 实例的中断状态,继续向下执行(正常退出(未发生异常))
public static void parkNanos(long nanos) {
if (nanos > 0)
U.park(false, nanos);
}

// 用于让本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态,并被投递到使用了 LockSupport 的具体产品维护的数据结构,等待被唤醒(LockSupport.unpark)、被中断(Thread#interrupt)、阻塞超时
//
// 本地线程进入阻塞状态,Thread 实例进入 TIMED_WAITING 状态后,能响应中断。线程被唤醒,重新获得 CPU 时间片后,不会抛出 InterruptedException 受检异常,但会保留 Thread 实例的中断状态,继续向下执行(正常退出(未发生异常))
public static void parkUntil(long deadline) {
U.park(true, deadline);
}

static final long getThreadId(Thread thread) {
return U.getLong(thread, TID);
}

private static final Unsafe U = Unsafe.getUnsafe();

private static final long PARKBLOCKER
= U.objectFieldOffset(Thread.class, "parkBlocker");

private static final long TID
= U.objectFieldOffset(Thread.class, "tid");

}


源码:java.util.concurrent.locks.LockSupport 源码解析
https://wangjia5289.github.io/2025/11/13/源码:java.util.concurrent.locks.LockSupport源码解析/
Author
咸阳猴🐒
Posted on
November 13, 2025
Licensed under