代码之家  ›  专栏  ›  技术社区  ›  akarnokd

Java中的虚假唤醒真的发生了吗?

  •  193
  • akarnokd  · 技术社区  · 15 年前

    看到各种与锁相关的问题,并且(几乎)总是找到“由于虚假唤醒而产生的循环”的术语 我想知道,有没有人经历过这样的唤醒(例如假设一个体面的硬件/软件环境)?

    我知道“虚假”一词没有明显的原因,但这种事件的原因是什么?

    ( 注意:我不是在质疑循环练习。)

    编辑: 帮助者问题(对于喜欢代码示例的人):

    如果我有以下程序,并运行它:

    public class Spurious {
        public static void main(String[] args) {
            Lock lock = new ReentrantLock();
            Condition cond = lock.newCondition();
            lock.lock();
            try {
                try {
                    cond.await();
                    System.out.println("Spurious wakeup!");
                } catch (InterruptedException ex) {
                    System.out.println("Just a regular interrupt.");
                }
            } finally {
                lock.unlock();
            }
        }
    }
    

    我能做些什么来唤醒这个 await 在不等待一个随机事件的情况下虚伪地向上?

    6 回复  |  直到 6 年前
        1
  •  192
  •   John Kugelman Michael Hodel    15 年前

    维基百科 article on spurious wakeups 有这个消息:

    这个 pthread_cond_wait() Linux中的函数是使用 futex 系统调用。Linux上的每个阻塞系统调用都会突然返回 EINTR 当进程接收到信号时。… pthread秒等待() 无法重新启动等待,因为它可能会错过一个真正的唤醒时间,它在外面 期货交易所 系统调用。只有调用方检查不变量才能避免这种竞争条件。因此,一个POSIX信号将产生一个虚假的唤醒。

    总结 :如果一个Linux进程收到信号,它的等待线程将各自享受一个好的、热的 虚假唤醒 .

    我买的。这是一种比通常给出的模糊的“它是为了表现”的原因更容易吞下的药丸。

        2
  •  21
  •   Mr.Dirty.Birdy    14 年前

    我有一个展示这种行为的生产系统。 线程等待队列中有消息的信号。 在繁忙时期,多达20%的唤醒是虚假的(即当它唤醒时,队列中没有任何内容)。 此线程是消息的唯一使用者。 它运行在LinuxSLES-10 8处理器盒上,并使用GCC4.1.2构建。 这些消息来自外部源,并且是异步处理的,因为如果系统没有足够快地读取它们,就会出现问题。

        3
  •  13
  •   Aniket Thakur    6 年前

    回答提提里的问题- 对! 它确实发生了,尽管 Wiki article 提到很多关于虚假唤醒的事情,我遇到的一个很好的解释是-

    想想看……与任何代码一样,线程调度程序可能会因底层硬件/软件中发生的异常情况而遇到临时中断。当然,应该注意这种情况发生得越少越好,但是由于没有100%健壮的软件这样的东西,所以假设这种情况可能发生是合理的,并且在调度程序检测到这种情况时(例如通过观察丢失的心跳)要注意优雅的恢复。

    现在,调度程序如何恢复,考虑到在停电期间,它可能会错过一些用于通知等待线程的信号?如果调度器什么都不做,上面提到的“不幸”线程将挂起,永远等待——为了避免这种情况,调度器只会向所有等待的线程发送一个信号。

    这使得有必要建立一个“契约”,让等待线程可以无理由地得到通知。准确地说,有一个原因——调度程序中断——但是由于线程被设计为(出于一个好的原因)忽略调度程序的内部实现细节,所以这个原因可能更好地表现为“虚假的”。

    我在读这个答案 Source 发现这是合理的。也读

    Spurious wakeups in Java and how to avoid them .

    附:上面的链接是我的个人博客,上面有关于虚假唤醒的更多细节。

        4
  •  8
  •   ReneS    13 年前

    只是为了增加这个。是的,它发生了,我花了三天时间在一台24核机器(JDK6)上寻找多线程问题的原因。10次执行中有4次没有任何模式。这从未发生在2核或8核上。

    研究了一些在线材料,这不是Java问题,而是一般罕见但预期的行为。

        5
  •  8
  •   Nathan Hughes    10 年前

    Cameron Purdy 写了一篇 blog post 不久前,关于被虚假唤醒问题击中的事情。所以是的,它发生了

    我猜测这是在规格(可能性),因为一些平台的局限性,Java部署?尽管我可能错了!

        6
  •  0
  •   Gili    6 年前

    https://stackoverflow.com/a/1461956/14731 包含一个很好的解释,说明为什么即使底层操作系统没有触发它们,您也需要防范虚假唤醒。有趣的是,这种解释适用于多种编程语言,包括Java。