Java中虚假的唤醒事件是否真的发生?

看到各种与锁定有关的问题和(几乎)总是找到'因为虚假唤醒'术语而导致的'循环'我想知道,有没有人经历过这种唤醒(假设一个体面的硬件/软件环境)?

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

(1注:我不质疑循环练习。)

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

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

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而不会永远等待随机事件?


关于虚假唤醒的维基百科文章有这个珍闻:

Linux中的pthread_cond_wait()函数是使用futex系统调用实现的。 当进程接收到信号时,Linux上的每个阻塞系统调用都会随EINTR突然返回。 ... pthread_cond_wait()无法重新启动等待,因为它在futex系统调用之外的很短时间内可能会错过真正的唤醒。 这种竞争条件只能通过调用者检查不变量来避免。 POSIX信号将因此产生虚假唤醒。

简介 :如果一个Linux进程发出信号,它的等待线程将各自享受一个不错的,热的虚假唤醒。

我买它。 这是一个容易吞咽的药丸,而不是通常模糊的“这是为了表现”的原因。


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


回答标题中的问题 - 是的! 它确实发生了。尽管Wiki文章提到了关于虚假唤醒的很多事情,但对于我遇到的同样的一个很好的解释如下 -

试想一下...就像任何代码一样,由于底层硬件/软件发生异常,线程调度器可能会经历暂时的停电。 当然,应该注意这种情况尽可能少发生,但由于没有100%强健的软件这样的事情,所以假设这种情况可能发生并且在调度器检测到这种情况时保持优雅恢复是合理的(例如,通过观察失踪的心跳)。

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

这使得有必要建立一个“合同”,可以在无理由的情况下通知等待线程。 确切地说,会有一个原因 - 调度程序停电 - 但是由于线程被设计(出于一个很好的理由)忽略了调度程序的内部实现细节,这个原因可能更好地表现为“虚假”。

我从Source阅读这个答案,发现它足够合理。 也读

Java中的虚假唤醒以及如何避免它们。

链接地址: http://www.djcxy.com/p/92109.html

上一篇: Do spurious wakeups in Java actually happen?

下一篇: Requiring a trait bound on the associated type of an inherited trait