java中wait()和notifyall()必须在synchronized块中调用同一对象,wait()释放锁并等待,notifyall()唤醒所有等待线程使其重新竞争锁;需用while循环判断条件以防虚假唤醒;notifyall()比notify()更安全,适用于多线程等待同一条件的场景。

Java 中使用 wait() 和 notifyAll() 实现线程同步,核心在于:它们必须在 synchronized 方法或代码块中调用,且操作的是同一个对象的监视器(monitor)。wait() 让当前线程释放锁并进入等待状态;notifyAll() 唤醒所有在该对象上等待的线程,由 JVM 重新竞争锁。
必须配合 synchronized 使用
wait() 和 notifyAll() 是 Object 类的方法,不是 Thread 类的。它们作用于对象的内置锁(intrinsic lock),所以调用前必须已获得该对象的锁——否则会抛出 IllegalMonitorStateException。
- 正确写法:在
synchronized(obj) { obj.wait(); }或synchronized实例方法内调用 - 错误写法:直接调用
obj.wait()而未加锁,或在静态方法中调用非静态对象的wait()却没同步该对象
wait() 要放在 while 循环里判断条件
不能用 if 判断后才 wait(),因为存在虚假唤醒(spurious wakeup)和条件变更竞争问题。线程被唤醒后,必须重新检查业务条件是否真正满足。
- 推荐模式:
while (!condition) { obj.wait(); } - 例如生产者-消费者场景中,消费者应循环检查缓冲区是否非空,而非只判断一次
notifyAll() 唤醒全部,但只有抢到锁的线程能继续执行
notifyAll() 不会让所有线程立刻运行,而是把它们从 WAITING 状态转为 BLOCKED 状态,等待重新获取锁。哪个线程先拿到锁、何时执行,由 JVM 调度决定。
- 相比
notify()(只唤醒一个),notifyAll()更安全,避免因唤醒错线程导致死锁或永久等待 - 典型适用场景:多个线程等待同一条件变化,比如资源池空闲、任务队列有新任务、共享标志位被设置等
简单示例:两个线程交替打印数字
以下是一个用 wait/notifyAll 控制线程顺序的最小可运行例子:
public class AlternatePrint {
private static final Object lock = new Object();
private static boolean printA = true;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 1; i {
for (int i = 2; i
注意:每次修改共享状态后都要调用 notifyAll(),确保等待方有机会重新检查条件。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











