Why wait, notify, and notifyAll methods are called from synchronized block or method in Java? (original) (raw)
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?
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:
IllegalMonitorStateException in Java which will occur if we don't call wait (), notify () or notifyAll () method from synchronized context.
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 Java, how 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?