locksupport 通过许可(permit)机制实现线程挂起与唤醒:park() 消耗许可(无则阻塞),unpark() 发放许可(可提前且不累积);无需 synchronized,支持精确唤醒、响应中断但不抛异常,须配合循环条件检查使用。

LockSupport 是 Java 并发包中用于线程挂起与唤醒的底层工具类,不依赖 synchronized,也不属于 Lock 接口体系,而是 JUC 中许多同步组件(如 AQS)的基石。 它的核心是“许可”(permit)机制:每个线程关联一个隐式的 permit,最多只有一个;park() 消耗 permit(若无则阻塞),unpark(Thread) 发放 permit(可提前发放,且允许多次调用,但只保留一个有效)。
如何挂起线程(park)
调用 LockSupport.park() 会使当前线程阻塞,直到发生以下任一情况:
- 其他线程对当前线程调用
unpark() - 当前线程被中断(此时 park 返回,但不会抛出 InterruptedException)
- 发生虚假唤醒(spurious wakeup,需配合循环检查条件)
推荐写法(带条件检查):
while (!conditionMet()) {
LockSupport.park(); // 挂起,等待被唤醒
}
注意:park() 不会响应中断异常,但可通过 Thread.interrupted() 主动检测中断状态。
如何唤醒指定线程(unpark)
LockSupport.unpark(Thread thread) 向目标线程发放一个 permit。关键特性:
- 可先于
park()调用 —— permit 会被保存,后续park()立即返回 - 多次
unpark()等价于一次(permit 不叠加) - 必须传入明确的 Thread 对象,不能唤醒“某个名字”的线程
示例:
Thread t = new Thread(() -> {
System.out.println("准备挂起");
LockSupport.park(); // 阻塞
System.out.println("被唤醒了");
});
t.start();
// 主线程稍作延迟后唤醒
Thread.sleep(100);
LockSupport.unpark(t); // 唤醒 t
常见陷阱与注意事项
- 无法判断 park 是否因 unpark 返回:park 返回时,可能是被 unpark、被中断,或虚假唤醒,务必结合条件变量使用循环检查
- unpark 作用于线程对象,不是线程 ID 或名称:若线程已终止,unpark 仍合法但无效(无影响)
-
不自动清理中断状态:park 不清除中断标志,需手动调用
Thread.interrupted()检查并处理 - 不可替代 Object.wait()/notify():LockSupport 无锁对象监视器语义,也不参与 synchronized 的等待队列管理
和 Object 监视器方法的区别
对比 wait()/notify():
- LockSupport 不要求在 synchronized 块中调用,无“持有锁才能调用”的限制
- 没有“唤醒丢失”问题(因为 permit 可预先发放)
- 不关联任何对象,更轻量,也更底层 —— 所以 AQS 用它实现 acquire/release 逻辑
但它也不提供 wait/notify 的内置条件队列、超时控制(park 有带 nanos 的重载)、以及线程调度公平性保证。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











