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

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

(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();
        }
    }
}

我能做些什么来唤醒这个等待,而不是永远等待一个随机事件?


当前回答

回答标题中的问题-是的!这种情况确实会发生。虽然维基上的文章提到了很多关于虚假唤醒的事情,但我遇到的一个很好的解释是

Just think of it... like any code, thread scheduler may experience temporary blackout due to something abnormal happening in underlying hardware / software. Of course, care should be taken for this to happen as rare as possible, but since there's no such thing as 100% robust software it is reasonable to assume this can happen and take care on the graceful recovery in case if scheduler detects this (eg by observing missing heartbeats). Now, how could scheduler recover, taking into account that during blackout it could miss some signals intended to notify waiting threads? If scheduler does nothing, mentioned "unlucky" threads will just hang, waiting forever - to avoid this, scheduler would simply send a signal to all the waiting threads. This makes it necessary to establish a "contract" that waiting thread can be notified without a reason. To be precise, there would be a reason - scheduler blackout - but since thread is designed (for a good reason) to be oblivious to scheduler internal implementation details, this reason is likely better to present as "spurious".

我读了这个来源的答案,发现它足够合理。也读

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

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

其他回答

卡梅伦·珀迪(Cameron Purdy)不久前写了一篇博文,讲述了自己被假醒问题困扰的经历。所以,是的,它发生了

我猜这是在规范中(作为一种可能性),因为Java部署在一些平台上的限制?虽然我可能错了!

维基百科上关于假醒的文章有这样的花边新闻:

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

概要:如果一个Linux进程收到信号,它的等待线程将享受一个漂亮的、热的伪唤醒。

我相信。这比通常给出的含糊的“为了性能”的理由更容易接受。

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

回答标题中的问题-是的!这种情况确实会发生。虽然维基上的文章提到了很多关于虚假唤醒的事情,但我遇到的一个很好的解释是

Just think of it... like any code, thread scheduler may experience temporary blackout due to something abnormal happening in underlying hardware / software. Of course, care should be taken for this to happen as rare as possible, but since there's no such thing as 100% robust software it is reasonable to assume this can happen and take care on the graceful recovery in case if scheduler detects this (eg by observing missing heartbeats). Now, how could scheduler recover, taking into account that during blackout it could miss some signals intended to notify waiting threads? If scheduler does nothing, mentioned "unlucky" threads will just hang, waiting forever - to avoid this, scheduler would simply send a signal to all the waiting threads. This makes it necessary to establish a "contract" that waiting thread can be notified without a reason. To be precise, there would be a reason - scheduler blackout - but since thread is designed (for a good reason) to be oblivious to scheduler internal implementation details, this reason is likely better to present as "spurious".

我读了这个来源的答案,发现它足够合理。也读

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

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

再加上这个。是的,这种情况会发生,我花了三天时间在24核机器(JDK 6)上寻找多线程问题的原因。10次执行中有4次遇到这种情况,没有任何模式。这从未发生在2核或8核上。

我研究了一些网上的资料,这不是Java的问题,而是一种普遍罕见但意料之中的行为。