Friday, September 15, 2023

Why wait, notify, and notifyAll methods are called from synchronized block or method in Java?

Most of the Java developers know that wait(), notify(), and notifyAll() methods of object class must have to be called inside synchronized method or synchronized block in Java but how many times we thought why? Recently this question was asked to in Java interview to one of my friend, he pondered for a moment and replied that if we don't call wait() or notify() method from synchronized context we will receive IllegalMonitorStateException in Java. He was right in terms of the behavior of language but as per him, the interviewer was not completely satisfied with the answer and wanted to explain to him more about it.

After the interview, he discussed the same questions with me and I thought he should have to tell the interviewer about race conditions between wait() and notify() in Java which could exist if we don't call them inside synchronized method or block. Let’s see how it could happen in a Java program.

It is also one of the popular thread interview questions and is often asked in both telephonic and face-to-face rounds of  Java developer interviews. So, if you are preparing for Java interviews, you should prepare questions like this and one book which can really help you is the Java Programming Interview exposed.

This is one of the rare books which covers almost all important topics of Java interviews like core Java, multi-threading, IO and NIO, and frameworks like Spring and Hibernate, etc. You can check it out here.





Why wait(), notify() and notifyAll() must be called from synchronized block or method in Java

We use wait(), notify(), or notifyAll() method mostly for inter-thread communication in Java. One thread is waiting after checking a condition e.g. In the classic Producer-Consumer problem, the Producer thread waits if the buffer is full and Consumer thread notify Producer thread after it creates a space in the buffer by consuming an element.




Calling notify() or notifyAll() methods issues a notification to a single or multiple threads that a condition has changed and once the notification thread leaves the synchronized block, all the threads which are waiting for fight for object lock on which they are waiting and lucky thread returns from wait() method after reacquiring the lock and proceed further.

Let’s divide this whole operation into steps to see a possibility of race condition between wait() and notify() method in Java, we will use the Produce Consumer thread example to understand the scenario better:

   1. The Producer thread tests the condition (buffer is full or not) and confirms that it must wait (after finding buffer is full).

   2. The Consumer thread sets the condition after consuming an element from a buffer.

   3. The Consumer thread calls the notify() method; this goes unheard since the Producer thread is not yet waiting.

   4. The Producer thread calls the wait() method and goes into a waiting state.

So due to race conditions here we potentially lost a notification and if we use buffer or just one element Produce thread will be waiting forever and your program will hang. You can further see these Java Multithreading courses to learn more bout race conditions and how to deal with them?

"wait notify and notifyall in java synchronized


Now let's think about how does this potential race condition get resolved? This race condition is resolved by using synchronized keyword and locking provided by Java. In order to call the wait (), notify () or notifyAll () methods in Java, we must have obtained the lock for the object on which we're calling the method.

Since the wait() method in Java also releases the lock prior to waiting and reacquires the lock prior to returning from the wait() method, we must use this lock to ensure that checking the condition (buffer is full or not) and setting the condition (taking element from the buffer) is atomic which can be achieved by using synchronized method or block in Java.

I am not sure if this is what the interviewer was actually expecting but this what I thought would at least make sense, please correct me If I wrong and let us know if there is any other convincing reason of calling wait(), notify(), or notifyAll method in Java.


Just to summarize we call wait (), notify () or notifyAll method in Java from synchronized method or synchronized block in Java to avoid:

1) IllegalMonitorStateException in Java which will occur if we don't call wait (), notify () or notifyAll () method from synchronized context.

2) Any potential race condition between wait and notify method in Java.


P. S. - Some of my other favorite interview discussions are Why String is immutable or final in Javahow HashMap works in Java, and what are differences between HashMap and hashtable in Java are. If you are preparing for Java interviews then you an also check them out for better preparation. 


And lastly one question for you? On which class wait and notify methods are defined? Thread class or Object class? Bonus point if you can explain why they are defined into that particular class?

31 comments :

Anand Vijayakumar said...

Nice explanation Javin!!!

More details on Thread Communication can be found by Clicking Here

Anand

tangjie said...

Interesting.But I don't think so. When you use wait or notify or notifyAll,your code pattern always look:
if some condition is true then wait/notify
the condition check and the wait/notify must be atomic.Or some condition is true, but when you invoke notify/wait,the condition has changed.

By the way,if you need notification not lost, you may use semaphore.

Anonymous said...

Hi Javin, though I was familiar with IllegalMonitorStateException if not calling wait(), notify() or notifyAll() from synchronized method or block but the real and more convincing reason "race condition" was simply great.race condition in wait and notify

Anonymous said...

Another important thing you can mentioned about wait method in java is that "always call wait method inside a loop in java" because you need to test the condition before waiting and after waiting.

Anonymous said...

Can you also let us know Why do we need to call wait() method in Java in loop ? Also when should we use notify() and notifyAll() method in Java. I always confuse between notify() and notifyAll() so really looking forward to your answer.

thoughts_anshul said...

thanks ........ grt info

Anonymous said...

thanks!
clean and precise

Javin @ thread interview questions said...

Thanks for you comment Anonymous, Good to know that you find information on wait and notify useful.

Anonymous said...

Just to summarize we call wait (), notify () or notifyAll method in Java from synchronized method or synchronized block in Java to avoid:
1) IllegalMonitorStateException in Java which will occur if we don't call wait (), notify () or notifyAll () method from synchronized context.

Here are you saying that IllegalMonitorStateException will be thrown if you do NOT call wait/notify from a synchronized method??? Please clarify what exactly you mean here. - thanks

Javin @ why wait and notify defined in Object class said...

@Anonymous. you got it right. it means "if you don't use synchronized method or block for calling wait() and notify() method it will throw IllegalMonitorStateException"

Anonymous said...

All is fine, i am bit not comfortable with point #3 The Consumer thread calls the notify () method; this goes unheard since the Producer thread is not yet waiting.

how come this notification lost.

Unknown said...

hi boss nice explanation & i hv a question,

can we invoke a specific thread (t2) from object monitor state(assume 5 threads like t1,t2...t5)

nitus said...

Operating system uses a concept of "monitor" and "waitset" to handle multiple threads accessing a resource.In java this concept is implemented using "synchronized" and "'wait','notify' and 'notifyAll'".Here monitor refer to 'synchronized' and waitset includes all three methods.(as far as my knowledge is true)

Amol Pawar said...

wait method is called to release lock which thread has acquired and thread can acquire intrinsic lock only within synchronized block. If wait method has called outside synchronized block it does not know which lock should it release if it is not holding any lock. I am really skeptical about race condition being the reason for wait method to call inside synchronized block

Jawahar said...

I have been following up this blog for a long time and I am very much impressed with it. Lovely articles, Clear explanation and much more. Thank you for the wonderful blog.

Javin @ producer consumer solution BlockingQueue said...

@Achappn M, thanks for comment. Since buffer is full, producer can no longer add new items into buffer, hence producer thread should wait, until consumer, create space in buffer after consuming some items.

Unknown said...

I think this is a simple question,you should only answer : wait notify notifyAll is designed by thread communication.

satpan said...

We can not release a lock(using wait()) or notifying other threads to acquire lock with owning lock for any object. So before calling this function we need to own a lock using synchronized block or synchronized method.

Vandna Thakur said...

I super like your bloggings. Whenever i feel doubt regarding any topic i always go for your articles.

Here in this article i have one doubt that when "The Consumer thread calls the notify () method; this goes unheard since the Producer thread is not yet waiting." why Producer thread not go in wait state?
how come this notification lost?

Anonymous said...

Wont the compiler throw error when we try to call wait/notify from non-synchronized method?

Nitin Taur said...

Javin your argument is incorrect. Lets assume that inside Object class wait() and notify() method where synchronized. Now your producer/consumer solution need not to call these method from synchronized block. Will producer/consume work correctly? No because 'is buffer empty condition check and wait' must be atomic. Similarly, 'buffer is not empty check and notify' must be atomic operation.

The reason for this restriction is in implementation of wait/notify mechanism. Every object, in addition to having an associated monitor, has an associated wait set. A wait set is a set of threads.

When an object is first created, its wait set is empty. Elementary actions that add threads to and remove threads from wait sets are atomic. Wait sets are manipulated solely through the methods Object.wait, Object.notify, and Object.notifyAll. To protect wait set while calling wait/notify these methods must be called from within synchronized block/method. This method are not synchronized in Object class to enforce programmer to couple condition (buffer is full/empty) and call to these method as atomic operation.

bhs said...

I am not sure if your producer-consumer example is correct from the standpoint of race condition. What I mean is, producer uses push(Object x) function to put something in queue -- so this will be synchronized for all producer threads. Similarly a consumer will use the pop() method to empty the queue -- so this will be synchronized only for all consumer threads. If either of these methods are not synchronized a race condition should occur between the different producers OR different consumers. Not sure if the race condition will occur between producer AND consumer cos both are working on a different set of locks. Even if I synchronize push() or pop() methods... the behavior between producer threads or consumer threads should be undefined.

Let me know if my thinking is right. I think @Nitin's and @Satpan's explanation make more sense to me.

But anyways, you are a great guy. Your tutorials are really helpful...so keep up the great work of teaching java in simple english...

Yadu said...

Race condition can happen even with wait()/notify()/notifyAll() being called from synchronized context. Race condition is prevented by conditional check on shared state of the object in loop around call of wait().

Example:
public void run() {
while (true) {
synchronized (jobs) {
// wait until at least one job is available
while (jobs.isEmpty()) {
try {
jobs.wait();
} catch (InterruptedException ie) { }
}
jobs.remove(0); // If we get here, we know that jobs is not empty
} }
}

Synchronized context is needed:
- to protect changable data of shared object
- thread needs to know what object it should take lock on after waking up from waiting state

Anonymous said...

Friends,
Simple answer is to let Java know which object lock should be released when wait method is called, as thread may have multiple lock. Calling wait outside sync context well leave Java clueless on which lock should release.

Thanks,
Gk

Manjunath.SV said...

Hi,

When thread calls wait on an object, it releases the lock it holds on that object and goes to wait, this is the reason we need to call wait inside synchronized block. when thread calls notify on that object, waiting thread come out of the object gets lock and continues execution. why we need to call notify inside synchronized block..? why thread needs lock on the object to wake up other thread waiting on the object..?

Anonymous said...

What will happen if multiple wait() will call notify() method and not notifyAll() ?

Anonymous said...


package qwerty;

class customer12 extends Thread
{
int amount=10000;
//synchronized
static Thread b;
void withdraw(int amount)
{
System.out.println("Going to withdraw");
if(this.amount<amount)
{
b=Thread.currentThread();
System.out.println("Less balance, waiting for Deposit");
try
{
this.wait();
}
catch(Exception e)
{
System.out.println(e);
}
}
this.amount-=amount;
System.out.println("Withdraw completed");
}
//synchronized
void deposit(int amount)
{
System.out.println("Going to deposit");
this.amount+=amount;
System.out.println("Deposit completed");
b.notify();
}
}


public class Qwerty {


public static void main(String[] args)
{
final customer12 c=new customer12();
class A extends Thread
{
public void run()
{
c.withdraw(15000);

}
}
class B extends Thread
{
public void run()
{
c.deposit(10000);
}
}
A a=new A();
a.start();
B b=new B();
b.start();
}

}





why isnt it working??//

Anonymous said...

Hi Anonymous, the problem in your code is on which you are calling the notify. I see that you are having a static Thread on which you are calling the notify, but the wait is happening on the main thread. I modified your code and changed it to notify() instead of b.notify() and it worked
Vikas

Vishwanatrh G T said...

As we know wait()/notify() methods are used for inter thread communication. In java Inter thread communication means acquiring or releasing the lock on an object. The lock on any object is enabled only when you use synchronized method/block.

If you call wait() in non-synchronised block/method, it dont had any lock on any object. So no question of releasing the lock at all. This is the same scenario for notify method too. So both these methods will throw IllegalMonitoringState exception.

M Chisty said...

Bad explanation.

Step 1 says "The Producer thread tests the condition (buffer is full or not) and confirms that it must wait (after finding buffer is full)"

And then Step 3 says "3. The Consumer thread calls the notify () method; this goes unheard since the Producer thread is not yet waiting."

Total contradiction. Step 1 says Producer must wait; but step 3 says Producer is not waiting. No better explanation than the original poor official JavaDoc.

This explanation does not follow the standard, compared to the other articles in this blog.

Anonymous said...

Hello Javin,
What if the variable used to set & check condition is declared volatile? If volatile, could we have got away from using the synchronized blocks?
Thanks.

Post a Comment