LockSupport的park/unpark是基于许可(permit)模型的底层线程阻塞/唤醒原语,不依赖锁和监视器,支持先unpark后park、精准唤醒指定线程、permit不可累积,且无需synchronized块。

LockSupport 的 park 和 unpark 是 JVM 提供的底层线程阻塞/唤醒原语,不依赖 synchronized 或 wait/notify,也不受锁状态影响,能实现更灵活、更精准的线程协作。
park 与 unpark 的核心特性
它们不是成对调用的“配对机制”,而是基于“许可(permit)”模型:每个线程默认持有 0 个 permit;unpark(Thread t) 给目标线程发放 1 个 permit(最多只存 1 个,重复调用不叠加);park() 会先检查当前线程是否有 permit —— 有则消耗掉并立即返回,无则挂起等待。
- permit 不可累积:连续两次
unpark(t)和一次park()效果等同于一次unpark+ 一次park - 无需同步块:可在任意位置调用,不抛出 InterruptedException(但可响应中断状态)
- 不会导致死锁:即使先
unpark后park,也能正确唤醒(这是它比 wait/notify 更可靠的关键)
精准控制挂起与唤醒的典型写法
避免因执行顺序导致的丢失唤醒,关键是让 park 前检查业务条件,并配合 volatile 变量或 CAS 判断是否需要挂起。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
// 示例:简单的一次性信号传递
volatile boolean ready = false;
Thread t = new Thread(() -> {
while (!ready) {
LockSupport.park(); // 挂起,直到被 unpark 或中断
}
System.out.println("已就绪,继续执行");
});
t.start();
// 主线程稍后发出信号
Thread.sleep(100);
ready = true;
LockSupport.unpark(t); // 精准唤醒指定线程
- 务必在 park 前加循环检查条件(即“自旋 + park”模式),防止虚假唤醒或条件未满足就挂起
- 使用 volatile 或原子变量保证条件可见性,避免因缓存导致 park 永久阻塞
- unpark 必须传入目标 Thread 实例(可提前保存引用),不能靠名字或 ID 查找
处理中断与清理场景
park 不会清除中断状态,调用后可通过 Thread.interrupted() 检查是否被中断,适合构建可取消的等待逻辑。
立即学习“Java免费学习笔记(深入)”;
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) {
if (someConditionMet()) break;
LockSupport.park();
if (Thread.currentThread().isInterrupted()) {
System.out.println("收到中断,退出等待");
return;
}
}
});
- park 返回后应主动检查中断状态,尤其在循环中,否则可能忽略中断请求
- 若需响应中断并抛出 InterruptedException,可手动封装:检测到中断后调用
Thread.currentThread().interrupt()再 throw - unpark 不会影响中断状态,也不会清除它
常见误用与避坑点
看似简单,但容易因理解偏差引发线程永远挂起或反复唤醒。
- 不要在 park 后直接依赖“一定被 unpark”——必须结合条件变量做兜底判断
- 避免在锁内调用 park:虽然语法允许,但可能阻塞时仍持有锁,造成死锁风险
- unpark 调用时机早于 park 仍有效,但若目标线程已终止,permit 会被丢弃(无副作用)
- JVM 内部大量使用它实现 AQS(如 ReentrantLock、Semaphore),日常开发建议优先用高层工具,仅在需极致控制时直接使用

















