wait不能防止死锁,但配合synchronized、while条件检查、notifyall及超时机制可有效避免逻辑死锁;必须在同步块中调用同一锁对象,且需重新验证唤醒后条件是否满足。

wait 方法本身不能“防止”死锁,但它在正确使用时,是避免因忙等、资源争抢不当导致的逻辑死锁(尤其是条件等待类死锁)的关键工具。真正起作用的是围绕 wait 的编程模式——核心在于释放锁 + 条件检查 + 合理唤醒。
必须在 synchronized 块中调用,并锁定同一对象
这是硬性前提,否则会抛 IllegalMonitorStateException。wait 会自动释放当前持有的锁,让其他线程有机会修改共享状态;notify/notifyAll 则需在持有同一把锁的前提下调用,确保唤醒动作与状态变更原子关联。
- 错误写法:在 synchronized(lockA) 中调用 lockB.wait() → 运行时报错
- 正确写法:synchronized(lock) { if (!condition) lock.wait(); }
- 所有涉及该条件的读写、等待、唤醒操作,都必须用同一个 lock 对象同步
永远配合 while 循环做条件检查
不能用 if 判断后直接 wait。因为线程被唤醒后,条件未必已满足(虚假唤醒、多线程竞争、notify 随机唤醒等),必须重新校验。
- 推荐模式:while (!condition) { lock.wait(); }
- 例如生产者-消费者中,“队列为空”时消费者 wait,被唤醒后仍需检查是否真非空
- 用 if 容易跳过条件检查,导致执行非法操作(如从空队列取元素)
优先用 notifyAll 而非 notify
当多个线程等待不同条件(如“有数据可消费”和“有空间可生产”)共用一个锁时,notify 可能只唤醒不相关的线程,造成其余线程永久等待。
- notifyAll 让所有等待者重新竞争锁并各自检查条件,更安全
- 虽有性能开销,但在多数业务场景下远小于死锁或逻辑错误的代价
- 只有在明确知道“只有一个线程符合条件且唤醒即能继续”时才谨慎用 notify
搭配超时机制应对异常场景
即使逻辑正确,外部干扰(如 notify 被遗漏、线程中断、系统异常)仍可能导致无限等待。wait(long timeout) 提供兜底保障。
- wait(5000) 表示最多等 5 秒,超时后跳出循环,可记录日志、重试或抛异常
- 配合中断处理:捕获 InterruptedException 后恢复中断状态 Thread.currentThread().interrupt()
- 避免“看似正常但实际卡死”的隐蔽问题
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











