Java中wait()和notify()必须在synchronized同步块中调用,否则抛IllegalMonitorStateException;wait()释放锁并进入等待队列,需用while循环防虚假唤醒;notifyAll()比notify()更安全,推荐用于多条件场景。

Java 中用 Object 类的 wait() 和 notify() 实现线程通信,核心是“在共享对象上协作”,必须配合 synchronized 使用,否则会抛出 IllegalMonitorStateException。
必须在 synchronized 同步块中调用
wait() 和 notify() 是 Object 的实例方法,调用前当前线程必须已获得该对象的监视器锁(即持有该对象的 intrinsic lock)。常见写法是:
synchronized (sharedObj) {
sharedObj.wait(); // 释放锁并进入等待队列
// 或
sharedObj.notify(); // 唤醒一个等待中的线程(不释放锁)
}
如果没加 synchronized,运行时直接报错。
wait() 会释放锁并挂起线程
wait() 执行时,当前线程会:
立即学习“Java免费学习笔记(深入)”;
- 立即释放它持有的该对象的锁
- 进入该对象的等待队列(wait set)
- 暂停执行,直到被
notify()或notifyAll()唤醒,或被中断、超时
注意:wait() 返回后,线程需重新竞争锁;获得锁后才继续执行后续代码。所以常配合 while 循环检查条件(防止虚假唤醒):
synchronized (lock) {
while (!conditionMet) {
lock.wait();
}
// 条件满足,执行业务逻辑
}
notify() 唤醒一个等待线程,notifyAll() 唤醒全部
notify() 随机唤醒等待队列中的一个线程(不保证顺序),notifyAll() 唤醒所有等待线程。推荐优先使用 notifyAll(),尤其当多个线程等待不同条件时——避免因唤醒错线程导致死锁或遗漏。
例如生产者-消费者场景中,若只用 notify(),可能唤醒另一个生产者而非消费者,造成持续阻塞。
典型使用模式:生产者-消费者模型
以一个共享缓冲区为例:
class Buffer {
private final Object lock = new Object();
private String data;
private boolean hasData = false;
void produce(String item) throws InterruptedException {
synchronized (lock) {
while (hasData) {
lock.wait(); // 缓冲区满,生产者等待
}
data = item;
hasData = true;
lock.notifyAll(); // 唤醒可能等待的消费者
}
}
String consume() throws InterruptedException {
synchronized (lock) {
while (!hasData) {
lock.wait(); // 缓冲区空,消费者等待
}
String result = data;
hasData = false;
lock.notifyAll(); // 唤醒可能等待的生产者
return result;
}
}
}
关键点:用 while 判断条件、每次修改状态后调用 notifyAll()、始终在同步块内操作。
不复杂但容易忽略细节:锁对象要唯一且共享,条件判断不能用 if,唤醒要选对目标,且不能在非同步上下文中调用。


















