Java 为什么线程会自动从wait()唤醒?

Java 为什么线程会自动从wait()唤醒?,java,concurrency,multithreading,Java,Concurrency,Multithreading,我想知道为什么java中的线程会自动从wait()唤醒。 这是一个设计决策吗?这是一种妥协吗 编辑:(摘自《实践中的Java并发》,第300页) wait甚至可以返回 “虚假”-不回应任何 线程调用notify 此外,提交人说: 这就像一个松软的烤面包机 使铃响的连接 当烤面包准备好的时候 有时它还没有准备好 这就是为什么您总是要像这样编写代码 synchronized(this){ while(!condition) wait(); } } 永远不会 sync

我想知道为什么java中的线程会自动从wait()唤醒。
这是一个设计决策吗?这是一种妥协吗

编辑:(摘自《实践中的Java并发》,第300页)

wait
甚至可以返回 “虚假”-不回应任何 线程调用notify

此外,提交人说:

这就像一个松软的烤面包机 使铃响的连接 当烤面包准备好的时候 有时它还没有准备好

这就是为什么您总是要像这样编写代码

synchronized(this){
    while(!condition)
        wait();
    }
}
永远不会

synchronized(this){
    if(!condition){
        wait();
    }
}
即使条件仅从
false
true

这些自发唤醒也称为“假唤醒”。在Java规范中,jvm实现允许(尽管不鼓励)虚假唤醒

之所以允许它们,是因为许多实现可能基于具有这种行为的pthreads(POSIX线程)。为什么?

根据David R.Butenhof的 用POSIX线程编程ISBN 0-201-63392-2:“这意味着 您等待一个条件变量,即 如果没有,等待可能(偶尔)返回 线程专门广播或 表示该条件变量。 虚假的唤醒可能听起来很奇怪, 但是在一些多处理器系统上, 使病情完全苏醒 可预测的速度可能会大大放缓 所有条件变量操作 引起虚假竞争的竞争条件 醒来应该被认为是罕见的。”


很难确切地回答这个问题,因为Java语言规范没有说明JVM实现为什么要这样做(它只指定它可以),但我发现

中的实际文章是关于POSIX线程的,但我认为假设Java中的线程在某种程度上受到POSIX线程行为的影响并不过分:

虚假唤醒听起来可能很奇怪,但在某些多处理器系统上,使条件唤醒完全可预测可能会大大降低所有条件变量操作的速度。导致虚假唤醒的比赛条件应该被认为是罕见的

这句话出自David R.Butenhof,他接着说:

尽管工作组中确实有一些成员认为,理论上可以想象会有这样的实施,但这并不是真正的原因。POSIX线程是实用的硬实时程序员和大部分学术研究人员之间紧张关系的结果。伪唤醒是一个学术计算机科学家集团的机制,它确保每个人都必须编写干净的代码来检查和验证谓词

但是(也许)大部分虚假的(或者至少是神秘的哲学意义上的)“效率”的论点在实时用户中更受欢迎,而真正的原因通常被排在第二位

“我已经考虑过很多次了,如何构建一个正确而实用的实现,它真的会有虚假的唤醒。我从来没能想出一个例子。但这并不意味着没有一个,这是一个很好的故事


不,请参考我的编辑。好的,我删除了我的评论,因为看起来你是对的。这很有意义。非常感谢。我想我们在大约60秒前就发布了这篇文章,但是大括号的作用是什么呢?正如问题所示,在处理谓词(等待的东西)的有状态代码中,虚假唤醒非常容易处理——这只是一个微不足道的更改。如果代码不处理谓词,不知道等待的是什么,并且是无状态的,那么修复它们就困难多了。
wait
/
notify
代码不处理谓词,并且是无状态的,因此放置代码以避免虚假唤醒是一个糟糕的选择。这就是标准没有要求它的原因。