为什么线程会自发地从 wait() 中唤醒?

2022-09-02 12:26:01

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

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

wait甚至允许“虚假地”返回 - 而不是响应任何线程调用通知。

此外,作者指出:

这就像一个连接松动的烤面包机,当吐司准备好时,铃铛会响起,但有时也会在它还没有准备好的时候响起。

这就是为什么你总是需要像这样编码

synchronized(this){
    while(!condition)
        wait();
    }
}

从不

synchronized(this){
    if(!condition){
        wait();
    }
}

即使条件仅从 转换为 。falsetrue


答案 1

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

允许使用它们的原因是,许多实现可能基于具有此行为的 pthreads(POSIX 线程)。为什么?

维基百科:

根据David R. Butenhof的《Programming with POSIX Threads ISBN 0-201-63392-2》一书:“这意味着当你等待一个条件变量时,当没有线程专门广播或发出条件变量信号时,等待可能会(偶尔)返回。虚假唤醒可能听起来很奇怪,但在某些多处理器系统上,使条件唤醒完全可预测可能会大大减慢所有条件变量操作的速度。导致虚假唤醒的竞争条件应被视为罕见。


答案 2

很难明确地回答这个问题,因为Java语言规范没有说明为什么JVM实现可能想要这样做(在本节中,它只指定它可以),但我在维基百科上发现了一个非常有趣的虚假唤醒历史

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

虚假唤醒可能听起来很奇怪,但在某些多处理器系统上,使条件唤醒完全可预测可能会大大减慢所有条件变量操作的速度。导致虚假唤醒的争用条件应视为罕见情况。

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

虽然工作组中确实有一些成员认为,从理论上讲,可以想象可能存在这样的实现,但这并不是真正的原因。(他们永远无法证明这一点。POSIX线程是务实的硬实时程序员和主要是学术研究人员之间紧张关系的结果。虚假唤醒是学术计算机科学家集团的机制,以确保每个人都必须编写检查和验证谓词的干净代码!

但是,(也许)很大程度上是虚假的(或者至少是晦涩的哲学)'效率'论点在实时人员中得到了更好的讨论,真正的原因通常被降级到理由的第二位。

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


推荐