Java中wait()和notify()是Object类的原生方法,用于线程协作,必须在synchronized块中调用;wait()释放锁并等待,notify()/notifyAll()唤醒线程;需用while循环检查条件以防虚假唤醒;推荐优先使用BlockingQueue等高阶并发工具。

Java 中 wait() 和 notify() 是 Object 类提供的原生方法,用于线程间协作——一个线程等待某个条件成立,另一个线程改变条件后唤醒它。它们必须在 synchronized 代码块或方法中调用,否则会抛出 IllegalMonitorStateException。
wait() 和 notify() 的基本使用规则
这两个方法不是 Thread 类的,而是所有对象都继承自 Object 的,所以操作的是「对象监视器(monitor)」。关键点:
-
wait()让当前线程释放锁、进入 WAITING 状态,并等待该对象上的notify()或notifyAll() -
notify()随机唤醒一个正在该对象上wait()的线程(不保证唤醒顺序) -
notifyAll()唤醒所有在该对象上等待的线程,更安全,推荐在多数场景下使用 - 调用前必须已持有该对象的锁(即在 synchronized(obj) 块内),否则报错
典型场景:生产者-消费者模型
用一个共享队列模拟,生产者加元素,消费者取元素,空时消费者等待,满时生产者等待:
class SharedBuffer {
private final List<String> buffer = new ArrayList<>();
private final int MAX_SIZE = 5;
public void produce(String item) throws InterruptedException {
synchronized (this) {
while (buffer.size() == MAX_SIZE) {
this.wait(); // 队列满,生产者等待
}
buffer.add(item);
System.out.println("Produced: " + item);
this.notifyAll(); // 通知可能等待的消费者
}
}
public String consume() throws InterruptedException {
synchronized (this) {
while (buffer.isEmpty()) {
this.wait(); // 队列空,消费者等待
}
String item = buffer.remove(0);
System.out.println("Consumed: " + item);
this.notifyAll(); // 通知可能等待的生产者
return item;
}
}
}
注意这里用了 while 而不是 if:防止虚假唤醒(spurious wakeup)或被错误唤醒后条件仍不满足。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
常见陷阱与注意事项
实际使用中容易出错,务必留意:
-
不能用在静态方法或类锁上随意 wait:如果 synchronized(Something.class),那就要用
Something.class.wait(),别混用实例和类锁 - notify() 不保证唤醒谁,也不保证立即执行:被唤醒线程需重新竞争锁,获得锁后才从 wait() 返回
- wait() 返回后要重新检查条件:因为可能被唤醒但条件仍未满足(比如多个消费者被 notifyAll 唤醒,但只有一个能取走元素)
- 不要在循环外调用 wait():单次 if 判断 + wait 可能跳过条件变化,导致永久等待
替代方案:优先考虑更高阶工具
虽然 wait/notify 是基础,但现代 Java 更推荐使用 java.util.concurrent 包中的工具,例如:
-
BlockingQueue(如ArrayBlockingQueue):内置线程安全的等待/唤醒逻辑,直接调用put()/take() -
Condition(配合ReentrantLock):比 wait/notify 更灵活,可定义多个等待队列 -
CountDownLatch、CyclicBarrier、Semaphore:针对特定同步场景设计,语义清晰、不易出错
除非写底层框架或有特殊需求,否则不建议手写 wait/notify 协作逻辑。

















