wait方法通过释放锁、条件等待和协作唤醒提升资源利用率,必须在synchronized块中调用,需用while循环防虚假唤醒,优先用notifyall(),建议设置超时避免死锁。

Java 中 wait 方法本身不直接“提高效率”,而是通过精准释放锁 + 条件等待 + 协作唤醒的机制,避免忙等待和无效轮询,从而在逻辑层面实现高效同步协作。关键不在速度,而在资源利用率和线程调度合理性。
必须搭配 synchronized 使用
wait() 只能在已持有对象监视器锁的前提下调用,否则抛出 IllegalMonitorStateException。它不是独立的同步工具,而是 synchronized 块内的协作指令:
- 进入 synchronized 块 → 获取锁 → 执行业务判断 → 满足等待条件 → 调用 wait() → 立即释放锁、进入 WAITING 状态
- 被 notify/notifyAll 唤醒后,线程需重新竞争该锁;只有抢到锁,才从 wait() 后继续执行
- 不能用在 Lock 接口(如 ReentrantLock)上——那是 Condition 的职责
永远用 while 循环包裹 wait()
虚假唤醒(spurious wakeup)是 JVM 允许的行为,即使没被显式 notify,wait 也可能返回。所以绝不能用 if 判断后 wait,必须用 while 检查条件是否真正满足:
- 错误写法:
if (queue.isEmpty()) wait();→ 可能醒来时仍为空,直接取数据会出错 - 正确写法:
while (queue.isEmpty()) wait();→ 醒来后再次确认,不满足就继续等 - 同理,生产者也应写
while (queue.size() == capacity) wait();
优先用 notifyAll() 而非 notify()
notify() 只唤醒一个等待线程,但无法保证唤醒的是“需要的那个角色”:
- 比如队列空时,多个消费者在 wait;此时生产者 notify(),可能唤醒另一个消费者而非刚插入数据的生产者想通知的对象
- 更危险的是:多个生产者和消费者共用同一锁对象时,notify() 可能唤醒同类型线程(如又唤醒一个生产者),导致死锁或饥饿
- notifyAll() 虽有开销,但确保所有相关方都重新评估状态,逻辑更健壮、不易出错
合理设置超时可防死锁
无参数 wait() 是无限等待,一旦 notify 被遗漏或逻辑出错,线程将永久挂起。加入超时是防御性编程的重要实践:
-
wait(5000)表示最多等 5 秒,超时后自动恢复,可做日志、重试或异常处理 - 特别适合外部依赖场景(如等待第三方服务响应、网络就绪等)
- 注意:超时返回不等于条件满足,仍需在 while 循环中检查真实状态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











