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()
?
What is the potential damage if it was possible to invoke wait()
outside a synchronized block, retaining it's semantics - suspending the caller thread?
A
wait()
only makes sense when there is also anotify()
, 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: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 isBut 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:
Better yet, don't mess with the synchronization primitives at all and work with the abstractions offered in the
java.util.concurrent
packages.The problem it may cause if you do not synchronize before
wait()
is as follows:makeChangeOnX()
and checks the while condition, and it istrue
(x.metCondition()
returnsfalse
, meansx.condition
isfalse
) so it will get inside it. Then just before thewait()
method, another thread goes tosetConditionToTrue()
and sets thex.condition
totrue
andnotifyAll()
.wait()
method (not affected by thenotifyAll()
that happened few moments before). In this case, the 1st thread will stay waiting for another thread to performsetConditionToTrue()
, but that might not happen again.@Rollerball is right. The
wait()
is called, so that the thread can wait for some condition to occur when thiswait()
call happens, the thread is forced to give up its lock.To give up something, you need to own it first. Thread needs to own the lock first. Hence the need to call it inside a
synchronized
method/block.Yes, I do agree with all the above answers regarding the potential damages/inconsistencies if you did not check the condition within
synchronized
method/block. However as @shrini1000 has pointed out, just callingwait()
within synchronized block will not avert this inconsistency from happening.Here is a nice read..
directly from this java oracle tutorial:
Let's illustrate what issues we would run into if
wait()
could be called outside of a synchronized block with a concrete example.Suppose we were to implement a blocking queue (I know, there is already one in the API :)
A first attempt (without synchronization) could look something along the lines below
This is what could potentially happen:
A consumer thread calls
take()
and sees that thebuffer.isEmpty()
.Before the consumer thread goes on to call
wait()
, a producer thread comes along and invokes a fullgive()
, that is,buffer.add(data); notify();
The consumer thread will now call
wait()
(and miss thenotify()
that was just called).If unlucky, the producer thread won't produce more
give()
as a result of the fact that the consumer thread never wakes up, and we have a dead-lock.Once you understand the issue, the solution is obvious: Use
synchronized
to make surenotify
is never called betweenisEmpty
andwait
.Without going into details: This synchronization issue is universal. As Michael Borgwardt points out, wait/notify is all about communication between threads, so you'll always end up with a race condition similar to the one described above. This is why the "only wait inside synchronized" rule is enforced.
A paragraph from the link posted by @Willie summarizes it quite well:
The predicate that the producer and consumer need to agree upon is in the above example
buffer.isEmpty()
. And the agreement is resolved by ensuring that the wait and notify are performed insynchronized
blocks.This post has been rewritten as an article here: Java: Why wait must be called in a synchronized block
When you call notify() from an object t, java notifies a particular t.wait() method. But, how does java search and notify a particular wait method.
java only looks into the synchronized block of code which was locked by object t. java cannot search the whole code to notify a particular t.wait().