我知道,我们使用这个习惯来等待处理虚假唤醒的通知:
synchronized (obj) {
while(somecond)
obj.wait();
}
如果出现虚假的唤醒,我们只需检查状态并返回等待。
但是,考虑一下情况:
是的,条件检查非常快,我们可以进行状态检查而不是obj.wait()
,可能性非常小。在这种情况下,我们可以放松obj.notify()
来电。
我是否误解了某些内容,或者我们真的可以使用此模式忽略通知?
答案 0 :(得分:8)
另一个线程需要锁定obj
才能调用obj.notify()
。如果您的线程在while循环中没有等待,它就无法拥有它,因为您的线程还需要obj
上的锁定在while循环中。
答案 1 :(得分:1)
obj.wait()
的调用在调用obj.notify()
之前不会返回。但是,如果另一个线程也在等待并且系统决定通知该线程,则可能无法响应obj.notify()
。如果您想避免这种情况,可以使用obj.notifyAll()
。如果只有一个线程正在等待,则不能使用此模式丢失通知。
请注意,除非持有锁,否则其他线程无法调用obj.notify()
。如果此线程正忙于检查条件,则它具有锁定,而另一个线程无法发出通知。 synchronized
块对于操作至关重要。
答案 2 :(得分:1)
在你出现的情况下,线程A正在评估条件,线程B正在调用notify
,以致线程A错过了notify
调用
这个场景不可能要调用notify
,因为它必须拥有线程A在同步块中使用的锁 - 只有一个线程可以拥有该锁一旦。有关详细信息,请参阅javadoc on notify
。
答案 3 :(得分:1)
我们正在检查对状态的修改,而obj
上的锁定由之后调用obj.notify()
的任何人保留。因此,假设我们目前正在检查状态,我们也会锁定obj
。
如果我们得到一个虚假的醒来,并且状态没有改变,那么没有人应该打电话给obj.notify()
。如果状态发生了变化,我们错过了obj.notify()
,那就无所谓了:对于所有打算,通过调用obj.notifiy()
进行虚假唤醒和唤醒现在具有相同的效果。
经验教训是,我们正在检查的状态只能被更改,而改变状态的人会锁定我们正在等待的对象。
答案 4 :(得分:1)
由于大多数答案都坚持不可能出现这种情况,因此值得调整:
在没有匹配的notify
线程的情况下,始终可以调用wait
。当通知线程在其他线程甚至进入整个notify
块之前调用synchronized
时,可能会发生这种情况。在任何线程进入notify
阻止synchronized
阻止wait
之前,甚至可能多次调用wait
方法,并且notify
- notify
机制不计算这些
因此,您必须处理错过synchronized
的案例,例如通过在调用wait
之前检查notify
块内的条件。但通过这样做,您可以添加处理和重置条件的可能性,而匹配的notify
确实正在等待。
因此,你必须始终意识到
的可能性notify
次调用synchronized(obj) {
while(somecond)
obj.wait();
}
这就是为什么正确的处理循环喜欢那样
notify
从应用程序的角度来看,过时的待定notify
与没有关联{{1}}调用的JVM / OS生成的虚假唤醒之间没有区别。这就是为什么没有尝试防止JVM的虚假唤醒。由于逻辑不会改变,这种努力将被浪费。