wait、notify、notifyAll是Object类中用于线程协作的方法,必须在synchronized块中调用;wait释放锁并等待,需用while循环检查条件防虚假唤醒;notify随机唤醒一个等待线程,notifyAll唤醒所有等待线程,后者更安全常用。

在 Java 中,wait、notify 和 notifyAll 是 Object 类提供的用于线程间协作的方法,必须在 synchronized 块或方法中调用,否则会抛出 IllegalMonitorStateException。它们的核心作用是让线程等待某个条件成立,或唤醒等待中的线程,实现生产者-消费者、线程协调等典型场景。
wait():释放锁并进入等待状态
wait() 会让当前线程释放它持有的同步监视器(即 synchronized 锁),进入该对象的等待队列,并暂停执行,直到被其他线程调用 notify() 或 notifyAll() 唤醒,或被中断、超时(如果是带参版本)。注意:不能用 if 判断后直接 wait,必须用 while 循环重检条件,防止虚假唤醒(spurious wakeup)。
- 调用前必须已获取该对象的锁(即在 synchronized 块内)
- 推荐写法:
while (!condition) { obj.wait(); } - 常见错误:用
if替代while,导致条件未满足就继续执行
notify():唤醒一个等待线程
notify() 从该对象的等待队列中随机选择一个线程唤醒(JVM 决定具体哪一个),被唤醒的线程不会立即执行,而是重新竞争该对象的锁;只有成功获取锁后,才能从 wait() 返回并继续执行。
- 只唤醒一个线程,适合“一对一”协作场景(如单个生产者对应单个消费者)
- 若等待队列为空,该调用无效果
- 无法指定唤醒哪个线程,也不保证公平性
notifyAll():唤醒所有等待线程
notifyAll() 唤醒在该对象上 wait() 的所有线程,它们全部进入锁竞争状态。虽然开销略大,但更安全,尤其适用于多个线程等待同一条件、且条件变化可能影响多个线程的情形(例如缓冲区由空变非空,多个消费者都可消费)。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
- 避免因只唤醒一个线程而遗漏其他符合条件的线程
- 配合
while条件检查,能自然过滤掉不满足条件的被唤醒线程 - 实际开发中,
notifyAll()比notify()更常用、更健壮
完整示例:生产者-消费者模式
以下是一个使用 wait/notifyAll 实现的简单共享缓冲区:
<font size="2"><pre class="brush:php;toolbar:false;">class SharedBuffer {
private final List<Integer> buffer = new ArrayList<>();
private final int capacity = 5;
public void produce(int item) throws InterruptedException {
synchronized (this) {
while (buffer.size() == capacity) {
this.wait(); // 缓冲区满,生产者等待
}
buffer.add(item);
System.out.println("Produced: " + item + ", size=" + buffer.size());
this.notifyAll(); // 通知所有等待者(可能有消费者在等)
}
}
public int consume() throws InterruptedException {
synchronized (this) {
while (buffer.isEmpty()) {
this.wait(); // 缓冲区空,消费者等待
}
int item = buffer.remove(0);
System.out.println("Consumed: " + item + ", size=" + buffer.size());
this.notifyAll(); // 通知所有等待者(可能有生产者在等)
return item;
}
}
}
关键点:所有操作都在 synchronized(this) 中;条件检查用 while;用 notifyAll 确保状态变更后所有相关线程都有机会响应。

















