java 线程未唤醒,多线程 - Java中的虚假唤醒真的发生了吗?

多线程 - Java中的虚假唤醒真的发生了吗?

看到各种锁定相关的问题和(几乎)总是找到'循环因为虚假的唤醒'术语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();

}

}

}

我怎么办才能在不等待随机事件的情况下虚假地唤醒await?

6个解决方案

188 votes

关于虚假唤醒的维基百科文章有这样一个小说:

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

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

我买它。 这是一个比通常模糊的“性能”原因更容易吞下的药丸。

John Kugelman answered 2019-03-14T05:54:15Z

20 votes

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

Mr.Dirty.Birdy answered 2019-03-14T05:54:41Z

12 votes

回答标题中的问题 - 是的! 它确实发生了。尽管维基文章提到了一个关于虚假唤醒的大量信息,但我遇到的一个很好的解释如下 -

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

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

这使得有必要建立一个“合同”,即无需理由就可以通知等待线程。 确切地说,有一个原因 - 调度程序停电 - 但由于线程被设计(有充分理由)无法调度内部实现细节,因此这个原因可能更好地表现为“虚假”。

我正在从Source阅读这个答案,并认为它足够合理。 还看了

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

Aniket Thakur answered 2019-03-14T05:55:43Z

8 votes

只是添加这个。 是的,它发生了,我花了三天时间在24核计算机(JDK 6)上搜索多线程问题的原因。 10次执行中有4次没有任何模式。 这从未发生在2核或8核上。

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

ReneS answered 2019-03-14T05:56:16Z

8 votes

Cameron Purdy不久前写了一篇关于受到虚假唤醒问题打击的博客文章。 是的,它发生了

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

oxbow_lakes answered 2019-03-14T05:56:49Z

0 votes

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

Gili answered 2019-03-14T05:57:15Z

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值