回答OP的问题
我该怎么做才能虚假地唤醒等待,而不必永远等待随机事件?
,没有任何虚假的唤醒可以唤醒此等待线程!
不管虚假唤醒可以或不可以发生在特定的平台,在OP的的情况下片断是积极不可能的Condition.await()
返回,看看行“虚假唤醒!” 在输出流中。
除非您使用非常特殊的Java类库
这是因为OpenJDK的标准ReentrantLock
方法newCondition()
返回嵌套AbstractQueuedSynchronizer
的Condition
接口的实现ConditionObject
(顺便说一句,它是Condition
此类库中唯一的接口实现),而ConditionObject
方法await()
本身检查条件是否不保持,没有任何虚假的唤醒会强制此方法错误地返回。
顺便说一下,您可以自己检查它,因为一旦AbstractQueuedSynchronizer
涉及到基于-的实现,就很容易模拟伪唤醒。
AbstractQueuedSynchronizer
使用低级LockSupport
的park
和unpark
方法,并且如果您LockSupport.unpark
在等待的线程上调用Condition
,则此操作无法与伪唤醒区分开。
稍微重构OP的代码段,
public class Spurious {
private static class AwaitingThread extends Thread {
@Override
public void run() {
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();
}
}
}
private static final int AMOUNT_OF_SPURIOUS_WAKEUPS = 10;
public static void main(String[] args) throws InterruptedException {
Thread awaitingThread = new AwaitingThread();
awaitingThread.start();
Thread.sleep(10000);
for(int i =0 ; i < AMOUNT_OF_SPURIOUS_WAKEUPS; i++)
LockSupport.unpark(awaitingThread);
Thread.sleep(10000);
if (awaitingThread.isAlive())
System.out.println("Even after " + AMOUNT_OF_SPURIOUS_WAKEUPS + " \"spurious wakeups\" the Condition is stil awaiting");
else
System.out.println("You are using very unusual implementation of java.util.concurrent.locks.Condition");
}
}
,并且无论unparking(main)线程尝试唤醒等待线程的努力程度如何,Condition.await()
在这种情况下该方法都不会返回。
接口Condition
的javadocCondition
中将讨论on 的等待方法的虚假唤醒。尽管确实如此,
等待条件时,允许进行虚假唤醒
然后
建议应用程序程序员始终假定它们可以发生,因此总是在循环中等待。
但后来补充说
一个实现是免费的,消除了虚假唤醒的可能性
和接口AbstractQueuedSynchronizer
的实现Condition
确实做到了这一点- 消除了任何可能的虚假唤醒。
这对于其他ConditionObject
的等待方法肯定适用。
因此,结论是:
我们应该始终Condition.await
在循环中进行调用,并检查条件是否不成立,但是对于标准的OpenJDK,Java类库是永远不会发生的。除非再次使用非常不寻常的Java类库(这一定是非常不寻常的,因为另一个众所周知的非OpenJDK Java类库,目前几乎已经绝种的GNU Classpath和Apache Harmony似乎与Condition
接口的标准实现相同)
pthread_cond_wait()
真正问题的JVM:“为什么pthread_cond_wait会有虚假的唤醒?” 。