在Java多线程编程中,线程的挂起与唤醒是实现线程间协作的基础操作。传统的Object类的wait和notify方法虽然能实现基础功能,但存在诸多使用限制,而LockSupport提供的park和unpark方法则能突破这些限制,构建更灵活的线程挂起机制。

wait/notify的局限性
wait和notify是Java早期提供的线程协作方法,使用时必须满足以下条件:
- 必须在synchronized修饰的同步代码块或同步方法中调用,否则会抛出IllegalMonitorStateException异常
- notify唤醒线程时,如果唤醒的线程还没有执行wait,那么这次唤醒会失效,后续该线程执行wait后会一直阻塞
- wait方法会释放当前持有的锁,而唤醒后需要重新竞争锁才能继续执行
这些限制使得wait/notify的使用场景比较受限,尤其是在复杂的线程协作逻辑中容易出现问题。
LockSupport的park与unpark核心特性
LockSupport是java.util.concurrent.locks包下的工具类,它的park和unpark方法用于阻塞和唤醒线程,核心特性如下:
- 不需要依赖任何锁对象,调用时不需要处于同步代码块中
- 支持先调用unpark再调用park,此时park方法不会阻塞线程,因为unpark会提前给线程发放一个许可
- 每个线程都有一个许可(permit),许可最多只有一个,重复调用unpark不会累加许可
- park方法会消耗当前线程的许可,如果没有许可就会阻塞,直到其他线程调用unpark发放许可或者被中断
基础使用示例
下面通过一个简单的示例演示park和unpark的基本用法:
import java.util.concurrent.locks.LockSupport;
public class LockSupportDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
System.out.println("线程开始执行,准备调用park挂起");
// 挂起当前线程,等待许可
LockSupport.park();
System.out.println("线程被唤醒,继续执行");
});
thread.start();
// 主线程休眠1秒,确保子线程先执行到park
Thread.sleep(1000);
System.out.println("主线程准备唤醒子线程");
// 给子线程发放许可,唤醒子线程
LockSupport.unpark(thread);
}
}
运行上述代码,输出顺序为:
- 线程开始执行,准备调用park挂起
- 主线程准备唤醒子线程
- 线程被唤醒,继续执行
先unpark后park的场景验证
wait/notify不支持先唤醒后等待,而LockSupport支持这种场景,示例如下:
import java.util.concurrent.locks.LockSupport;
public class LockSupportOrderDemo {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
// 休眠2秒,确保主线程先执行unpark
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("子线程准备调用park");
// 此时许可已经被主线程发放,park不会阻塞
LockSupport.park();
System.out.println("子线程没有阻塞,直接执行到这里");
});
thread.start();
System.out.println("主线程先调用unpark发放许可");
LockSupport.unpark(thread);
}
}
运行后可以看到,子线程即使后调用park,也不会进入阻塞状态,因为之前已经收到了unpark发放的许可。
对比wait/notify的灵活性体现
通过以下对比可以明确LockSupport的优势:
| 对比维度 | wait/notify | LockSupport park/unpark |
|---|---|---|
| 依赖条件 | 必须配合synchronized锁使用 | 无依赖,可直接调用 |
| 唤醒顺序 | 必须先wait后notify,否则唤醒失效 | 支持先unpark后park,唤醒不会失效 |
| 锁释放 | wait会释放持有的锁 | park不会释放任何锁 |
| 精确唤醒 | notify随机唤醒一个等待线程,notifyAll唤醒所有 | unpark可以指定具体线程进行唤醒 |
注意事项
使用LockSupport时需要注意以下几点:
- park方法响应中断,但不会抛出InterruptedException,需要通过Thread.interrupted()方法检查中断状态
- 不要将park用在同步代码块中替代wait,两者的设计目标不同,LockSupport更适合作为并发工具类的底层支撑
- 连续多次调用unpark只会保留一个许可,不会让许可累加,因此多次park还是会阻塞
在实际开发中,如果需要更灵活的线程挂起与唤醒控制,尤其是需要突破wait/notify的顺序限制和锁依赖时,LockSupport的park和unpark是更合适的选择,很多并发容器和同步工具类比如AQS的底层都使用了LockSupport来实现线程阻塞和唤醒逻辑。
LockSupportparkunparkwait_notify线程挂起修改时间:2026-06-24 19:24:37