Why must wait() always be in synchronized block

JavaMultithreadingConcurrencyWait

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

> What is the potential damage if it was possible to invoke wait() outside a synchronized block, retaining it's semantics - suspending the caller thread?

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

class BlockingQueue {
    Queue<String> buffer = new LinkedList<String>();
    
    public void give(String data) {
        buffer.add(data);
        notify();                   // Since someone may be waiting in take!
    }
    
    public String take() throws InterruptedException {
        while (buffer.isEmpty())    // don't use "if" due to spurious wakeups.
            wait();
        return buffer.remove();
    }
}

This is what could potentially happen:

  1. A consumer thread calls take() and sees that the buffer.isEmpty().

  2. Before the consumer thread goes on to call wait(), a producer thread comes along and invokes a full give(), that is, buffer.add(data); notify();

  3. The consumer thread will now call wait() (and miss the notify() that was just called).

  4. 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 sure notify is never called between isEmpty and wait.

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:

> You need an absolute guarantee that the waiter and the notifier agree about the state of the predicate. The waiter checks the state of the predicate at some point slightly BEFORE it goes to sleep, but it depends for correctness on the predicate being true WHEN it goes to sleep. There's a period of vulnerability between those two events, which can break the program.

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 in synchronized blocks.


This post has been rewritten as an article here: Java: Why wait must be called in a synchronized block

Solution 2 - Java

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:

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();
    }
}

Better yet, don't mess with the synchronization primitives at all and work with the abstractions offered in the java.util.concurrent packages.

Solution 3 - Java

@Rollerball is right. The wait() is called, so that the thread can wait for some condition to occur when this wait() 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 calling wait() within synchronized block will not avert this inconsistency from happening.

Here is a nice read..

Solution 4 - Java

The problem it may cause if you do not synchronize before wait() is as follows:

  1. If the 1st thread goes into makeChangeOnX() and checks the while condition, and it is true (x.metCondition() returns false, means x.condition is false) so it will get inside it. Then just before the wait() method, another thread goes to setConditionToTrue() and sets the x.condition to true and notifyAll().
  2. Then only after that, the 1st thread will enter his wait() method (not affected by the notifyAll() that happened few moments before). In this case, the 1st thread will stay waiting for another thread to perform setConditionToTrue(), but that might not happen again.

>But if you put synchronized before the methods that change the object state, this will not happen.

class A {

	private Object X;
	
	makeChangeOnX(){
		while (! x.getCondition()){
			wait();
			}
		// Do the change
	}
	
	setConditionToTrue(){
		x.condition = true;	
		notifyAll();

	}
	setConditionToFalse(){
		x.condition = false;
		notifyAll();
	}
	bool getCondition(){
	    return x.condition;
    }
}

Solution 5 - Java

We all know that wait(), notify() and notifyAll() methods are used for inter-threaded communications. To get rid of missed signal and spurious wake up problems, waiting thread always waits on some conditions. e.g.-

boolean wasNotified = false;
while(!wasNotified) {
    wait();
}

Then notifying thread sets wasNotified variable to true and notify.

Every thread has their local cache so all the changes first get written there and then promoted to main memory gradually.

Had these methods not invoked within synchronized block, the wasNotified variable would not be flushed into main memory and would be there in thread's local cache so the waiting thread will keep waiting for the signal although it was reset by notifying thread.

To fix these types of problems, these methods are always invoked inside synchronized block which assures that when synchronized block starts then everything will be read from main memory and will be flushed into main memory before exiting the synchronized block.

synchronized(monitor) {
    boolean wasNotified = false;
    while(!wasNotified) {
        wait();
    }
}

Thanks, hope it clarifies.

Solution 6 - Java

This basically has to do with the hardware architecture (i.e. RAM and caches).

If you don't use synchronized together with wait() or notify(), another thread could enter the same block instead of waiting for the monitor to enter it. Moreover, when e.g. accessing an array without a synchronized block, another thread may not see the changement to it...actually another thread will not see any changements to it when it already has a copy of the array in the x-level cache (a.k.a. 1st/2nd/3rd-level caches) of the thread handling CPU core.

But synchronized blocks are only one side of the medal: If you actually access an object within a synchronized context from a non-synchronized context, the object still won't be synchronized even within a synchronized block, because it holds an own copy of the object in its cache. I wrote about this issues here: https://stackoverflow.com/a/21462631 and https://stackoverflow.com/questions/21458625/when-a-lock-holds-a-non-final-object-can-the-objects-reference-still-be-change

Furthermore, I'm convinced that the x-level caches are responsible for most non-reproducible runtime errors. That's because the developers usually don't learn the low-level stuff, like how CPU's work or how the memory hierarchy affects the running of applications: http://en.wikipedia.org/wiki/Memory_hierarchy

It remains a riddle why programming classes don't start with memory hierarchy and CPU architecture first. "Hello world" won't help here. ;)

Solution 7 - Java

as per docs: > The current thread must own this object's monitor. The thread releases > ownership of this monitor.

wait() method simply means it releases the lock on the object. So the object will be locked only within the synchronized block/method. If thread is outside the sync block means it's not locked, if it's not locked then what would you release on the object?

Solution 8 - Java

Thread wait on the monitoring object (object used by synchronization block), There can be n number of monitoring object in whole journey of a single thread. If Thread wait outside the synchronization block then there is no monitoring object and also other thread notify to access for the monitoring object, so how would the thread outside the synchronization block would know that it has been notified. This is also one of the reason that wait(), notify() and notifyAll() are in object class rather than thread class.

Basically the monitoring object is common resource here for all the threads, and monitoring objects can only be available in synchronization block.

class A {
   int a = 0;
  //something......
  public void add() {
   synchronization(this) {
      //this is your monitoring object and thread has to wait to gain lock on **this**
       }
  }

Solution 9 - Java

directly from this java oracle tutorial:

> When a thread invokes d.wait, it must own the intrinsic lock for d — > otherwise an error is thrown. Invoking wait inside a synchronized > method is a simple way to acquire the intrinsic lock.

Solution 10 - Java

When you call notify() on 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().

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiondiyView Question on Stackoverflow
Solution 1 - JavaaioobeView Answer on Stackoverflow
Solution 2 - JavaMichael BorgwardtView Answer on Stackoverflow
Solution 3 - Javaashoka.devanampriyaView Answer on Stackoverflow
Solution 4 - JavaShay.GView Answer on Stackoverflow
Solution 5 - JavaAavesh YadavView Answer on Stackoverflow
Solution 6 - JavaMarcusView Answer on Stackoverflow
Solution 7 - JavaArun RaajView Answer on Stackoverflow
Solution 8 - Javaaditya lathView Answer on Stackoverflow
Solution 9 - JavaRollerballView Answer on Stackoverflow
Solution 10 - Javalakshman reddyView Answer on Stackoverflow