LockSupport 的 park/unpark 是基于许可制的线程阻塞/唤醒机制,每个线程有初始为0的permit,unpark设为1(不累积),park消耗permit或阻塞,支持先unpark后park、无需锁、可响应中断但不抛异常,需配合条件循环检查使用。

LockSupport 的 park 和 unpark 是 Java 中最底层的线程阻塞/唤醒工具,不依赖对象监视器(即不用 synchronized),也不受锁状态影响,适合实现自定义同步器(如 AQS)或精细控制线程协作。
park/unpark 的核心特点
与 wait/notify 不同,park 和 unpark 是“许可制”:每个线程有一个隐式的许可(permit),初始为 0;unpark 将 permit 设为 1(最多 1,多次调用只保留一次);park 若 permit 为 1,则消耗它并立即返回,否则阻塞当前线程直到被唤醒或中断。
-
park()可响应中断,但不会抛出InterruptedException,而是通过Thread.interrupted()检查 -
unpark(Thread t)可以在park()之前调用,许可会“累积”(实际是设为 1),避免因时序导致的丢失唤醒 - 无需持有任何锁,也不关联特定对象,调用更自由
基本挂起与唤醒示例
下面是一个典型的一对一线程协作:线程 B 等待线程 A 完成某项工作后被唤醒:
Thread a = new Thread(() -> {
System.out.println("A: 开始工作");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println("A: 工作完成,唤醒 B");
LockSupport.unpark(b); // 唤醒 b
});
Thread b = new Thread(() -> {
System.out.println("B: 准备挂起");
LockSupport.park(); // 阻塞,等待许可
System.out.println("B: 被唤醒,继续执行");
});
b.start();
a.start();
注意:必须先启动 b 再启动 a,否则 unpark 可能发生在 park 之前——这没问题,因为许可会被保留。
立即学习“Java免费学习笔记(深入)”;
带条件判断的安全挂起
实际中常需“检查条件 + 挂起”,避免虚假唤醒或竞态。推荐模式是循环检查条件,并在 park 前再次确认:
AtomicBoolean ready = new AtomicBoolean(false);
Thread waiter = new Thread(() -> {
while (!ready.get()) {
LockSupport.park(); // 挂起
// 被唤醒后重新检查,防止 spuriously wake up
}
System.out.println("条件满足,继续执行");
});
Thread signaler = new Thread(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) {}
ready.set(true);
LockSupport.unpark(waiter);
});
这种写法类似 while (!condition) park(),是使用 park/unpark 的标准实践。
结合中断处理的健壮写法
若线程可能被中断,应在 park 后检查中断状态,并按需退出:
- 调用
Thread.interrupted()清除中断标志并判断是否被中断 - 若中断发生,可选择抛出
InterruptedException或自行处理 - 注意:park 不会清除中断状态,需手动处理
Thread t = Thread.currentThread();
while (!done && !t.isInterrupted()) {
LockSupport.park();
if (Thread.interrupted()) { // 检查并清除中断
System.out.println("收到中断,退出等待");
break;
}
}
不复杂但容易忽略细节:permit 是线程级别的、不可重入、不自动清理,合理配对 unpark/park 并配合条件检查,就能写出可靠、低开销的线程协作逻辑。


















