【问题标题】:Why do threads spontaneously awake from wait()?为什么线程会自发地从 wait() 中唤醒?
【发布时间】:2010-03-29 20:20:12
【问题描述】:

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

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

wait 甚至被允许返回 “虚假地”——不回应任何 线程调用通知。

作者进一步指出:

这就像一个松散的烤面包机 使铃声响起的连接 当吐司准备好时 有时它还没有准备好。

这就是为什么你总是必须像这样编写代码的原因

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

永远不会

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

即使条件仅从 falsetrue

【问题讨论】:

  • 不,请参考我的编辑..
  • 好吧,我删除了我的评论,因为看起来你是对的。

标签: java concurrency multithreading


【解决方案1】:

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

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

Wikipedia:

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

【讨论】:

  • 这很有意义。谢谢!
  • 我认为我们发布此消息的间隔大约为 60 秒
  • 但是大括号是怎么回事?
  • 如问题所示,在处理谓词(等待的东西)的有状态代码中非常很容易处理虚假唤醒——这只是一个微不足道的变化。在不处理谓词、不知道在等待什么并且是无状态的代码中修复它们会更加困难。 wait/notify 代码不处理谓词并且是无状态的,因此放置代码以避免虚假唤醒的地方是一个糟糕的选择。这就是标准不要求这样做的原因。
  • 所以基本上你不应该在没有条件的情况下编写代码wait()?
【解决方案2】:

很难明确回答这个问题,因为 Java 语言规范没有说明 为什么 JVM 实现可能想要这样做(它只指定它可以,in this section),但我发现a pretty interesting history of spurious wake-ups on Wikipedia.

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

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

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

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

“但是(也许)很大程度上是虚假的(或至少是神秘的哲学上的)'效率'论点在实时人员中得到了更好的认可,而真正的原因通常在基本原理中排在第二位。

“我多次考虑过如何构建一个正确且实用的实现,该实现会真正产生虚假唤醒。我从未设法构建一个示例。但这并不意味着没有,而且这是一个很好的故事。

【讨论】:

    猜你喜欢
    • 2019-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-06
    相关资源
    最近更新 更多