wait方法必须与synchronized和notify/notifyAll配合使用,通过“等待-唤醒”机制实现线程协作,核心是锁保护的while循环条件判断与精准状态变更后的唤醒。

wait 方法本身不能单独实现异步转同步,必须配合 synchronized 和 notify/notifyAll 使用,核心是“等待-唤醒”协作机制。关键不在于调用 wait,而在于如何构建线程安全的等待条件和精准唤醒逻辑。
wait/notify 必须成对出现在 synchronized 块中
wait 会释放当前对象锁,但前提是当前线程已持有该锁;否则抛出 IllegalMonitorStateException。notify 同理,也必须在 synchronized 块内调用,且唤醒的是同一把锁上 wait 的线程。
- 所有共享状态(如完成标志、结果容器)必须被同一把锁保护
- 不能用 if 判断等待条件,必须用 while 循环——防止虚假唤醒(spurious wakeup)
- notify 应在状态真正变更后调用,且最好紧随状态修改语句之后
典型结构:标志位 + while 循环 + 锁保护
以“等待异步任务完成”为例,定义一个 volatile boolean done = false 和 Object lock = new Object():
- 异步回调里:synchronized(lock) { done = true; lock.notify(); }
- 同步等待方:synchronized(lock) { while (!done) lock.wait(); }
- 如果需超时控制,用 wait(timeout) 并检查返回后 done 是否为 true
避免常见陷阱
wait 不是 sleep,它依赖 notify 触发;若 notify 被提前调用(发生在 wait 之前),该次唤醒就丢失了,线程将永远阻塞。因此:
立即学习“Java免费学习笔记(深入)”;
- 确保 notify 总是在 wait 执行之后发生——通常靠执行顺序或额外协调(如 CountDownLatch 更稳妥)
- 不要在多个无关逻辑共用同一把锁,否则 notify 可能唤醒错误线程
- 慎用 notify():它只唤醒一个线程,若存在多个等待者且逻辑不对称,优先选 notifyAll()
与 CountDownLatch 对比更适用的场景
wait/notify 更适合“状态驱动”的细粒度协作,比如生产者-消费者、任务完成通知、资源就绪等待等;而 CountDownLatch 更适合“计数归零即释放”的一次性屏障场景。若只是简单等待一个异步操作结束,CountDownLatch 语义更清晰、不易出错;若需复用等待逻辑或响应多种状态变化,wait/notify 更灵活但要求更高。


















