[java - wait() 虚假唤醒]

对!while (!isDone) { wait(); } 这个循环的核心作用就是防止“虚假唤醒”,这是多线程编程中一个非常重要的细节。

什么是“虚假唤醒”?

Java 中,线程调用 wait() 后可能会在没有被其他线程调用 notify()/notifyAll() 的情况下被唤醒,这种现象就是“虚假唤醒”(spurious wakeup)。
它不是程序错误导致的,而是操作系统或 JVM 内部的调度机制引起的(比如线程调度的“惊群效应”,或某些底层优化)。简单说:wait() 可能无缘无故地醒过来

为什么需要 while 循环来防虚假唤醒?

假设你把代码写成 if (!isDone) { wait(); }(用 if 而不是 while),会出现什么问题?

// 错误示例:用if判断,可能被虚假唤醒
public synchronized V get() throws Exception {
    if (!isDone) { 
        wait(); // 若此处被虚假唤醒,直接跳出if
    }
    return result;
}
  • 正常情况:线程A执行完任务,调用 notifyAll(),主线程被唤醒,isDonetrue,返回结果——没问题。
  • 虚假唤醒情况:主线程在 wait() 时被无故唤醒,但此时 isDone 仍然为 false(任务根本没完成)。由于用了 if,只会判断一次,唤醒后直接跳出 if,返回 result(可能是 null 或错误值),导致逻辑错误。

while 循环如何解决问题?

while (!isDone) { wait(); } 时,每次线程从 wait() 中醒来(无论正常唤醒还是虚假唤醒),都会重新检查 isDone 的值

  • 如果是正常唤醒:isDone 已经被设为 true,循环条件不成立,跳出循环,返回正确结果。
  • 如果是虚假唤醒:isDone 仍然为 false,循环条件成立,会再次执行 wait() 继续阻塞,直到任务真的完成并被正常唤醒。

这就像你在等外卖时,每次被“敲门声”吵醒(无论真有人敲门还是听错了),都会先通过猫眼确认是不是外卖员(检查 isDone),不是的话就继续睡——确保不会白跑一趟。

结合你的代码,总结 while 循环的必要性

  • 你的 MyFutureTask 中,get() 方法的核心逻辑是“直到任务完成(isDone=true),才返回结果”。
  • 虚假唤醒会破坏这个逻辑(让线程在任务未完成时就继续执行)。
  • while 循环通过“唤醒后重新检查条件”,确保只有当 isDone 真的为 true 时,才会退出等待——完美解决虚假唤醒问题。

这也是 Java 官方文档中明确推荐的写法:永远在 while 循环中使用 wait(),而不是 if,目的就是防止虚假唤醒。

posted @ 2025-10-27 23:55  十三山入秋  阅读(5)  评论(0)    收藏  举报