问题描述
我们都知道为了调用 Object.wait()
,这个调用必须放在同步块中,否则一个IllegalMonitorStateException
被抛出.但是做出这个限制的原因是什么?我知道 wait()
释放了监视器,但是为什么我们需要通过使特定块同步然后显式获取监视器通过调用 wait()
?
We all know that in order to invoke Object.wait()
, this call must be placed in synchronized block, otherwise an IllegalMonitorStateException
is thrown. But what's the reason for making this restriction? I know that wait()
releases the monitor, but why do we need to explicitly acquire the monitor by making particular block synchronized and then release the monitor by calling wait()
?
如果可以在同步块之外调用 wait()
并保留其语义 - 挂起调用者线程,那么潜在的损害是什么?
What is the potential damage if it was possible to invoke wait()
outside a synchronized block, retaining it's semantics - suspending the caller thread?
推荐答案
wait()
只在有 notify()
时才有意义,所以它总是关于线程之间的通信,这需要同步才能正常工作.人们可能会争辩说这应该是隐含的,但这并没有真正的帮助,原因如下:
A wait()
only makes sense when there is also a notify()
, so it's always about communication between threads, and that needs synchronization to work correctly. One could argue that this should be implicit, but that would not really help, for the following reason:
从语义上讲,您永远不会只是 wait()
.你需要满足一些条件,如果不是,你就等到它满足.所以你真正要做的是
Semantically, you never just wait()
. You need some condition to be satsified, and if it is not, you wait until it is. So what you really do is
if(!condition){
wait();
}
但是条件是由一个单独的线程设置的,所以为了使这项工作正常工作,您需要同步.
But the condition is being set by a separate thread, so in order to have this work correctly you need synchronization.
它还有一些问题,仅仅因为您的线程退出等待并不意味着您正在寻找的条件为真:
A couple more things wrong with it, where just because your thread quit waiting doesn't mean the condition you are looking for is true:
你可以得到虚假唤醒(意味着一个线程可以在没有收到通知的情况下从等待中唤醒),或者
You can get spurious wakeups (meaning that a thread can wake up from waiting without ever having received a notification), or
条件可以设置,但第三个线程在等待线程唤醒(并重新获取监视器)时再次使条件为假.
The condition can get set, but a third thread makes the condition false again by the time the waiting thread wakes up (and reacquires the monitor).
为了处理这些情况,您真正需要的是总是这种变化:
To deal with these cases what you really need is always some variation of this:
synchronized(lock){
while(!condition){
lock.wait();
}
}
更好的是,根本不要弄乱同步原语,而是使用 java.util.concurrent
包中提供的抽象.
Better yet, don't mess with the synchronization primitives at all and work with the abstractions offered in the java.util.concurrent
packages.
这篇关于为什么必须 wait() 总是在同步块中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!