Saturday, December 10, 2022

10 points about wait(), notify() and notifyAll() in Java Thread?

If you ask me one concept in Java that is so obvious yet most misunderstood, I would say the wait(), notify(), and notifyAll() methods. They are quite obvious because they are one of the three methods of a total of 9 methods from java.lang.Object but if you ask when to use the wait(), notify() and notfiyAll() in Java, not many Java developers can answer with surety. The number will go down dramatically if you ask them to solve the producer-consumer problem using wait() and notify()

Many will use if block instead of while loop, many others will get confused on which object they should call wait() and notify()method? Some of them even succeed in creating livelock, deadlock, and other multithreading issues.

That's why it's become very important to know as much as possible about these three methods. In this article, I am going to share some practical tips and points about wait(), notify(), and notifyAll() in Java.

Two books, which helped me a lot while understanding this core concept are Effective Java and Core Java Volume 1 - Fundamentals by Cay S. Horstmann. Both of them explain this confusing concept in simple language. The two items on Effective Java is the two of the best piece to read on this topic.



wait() vs notify() vs notifyAll in threading

Let's see some key points about these fundamental methods in Java especially from a multi-threading and concurrency perspectives.

1. Though wait, notify, and notifyAll is related to threads they are not defined in java.lang.Thread class, instead they are defined in the Object class. If you are wondering why? then you should read why the wait() and notify() are defined in the Object class in Java.


2. You must call the wait(), notify() and notifyAll() methods from a synchronized context in Java i.e. inside the synchronized method or a synchronized block. The thread must hold the lock on the object it is going to call the wait() or notify() method and that is acquired when it enters into a synchronized context.



If you call it without holding a lock then they will throw IllegalMonitorStateException in Java. If you are curious why is this restriction in place then check this article to learn more.


3. You must call the wait() method from inside a loop, don't call with an if block because a thread can sporadically awake from the wait state without being notified by another party. If you use if block then this could result in a bug. You can also see Item 69 of Effective Java for more details.

Here is the standard idiom to call the wait() method in Java:

synchronized (theSharedObject) {
  while (condition) {
   theSharedObject.wait(); 
  }
 // do something
}


4. When a thread calls the wait() method in Java, it goes to the wait state by releasing the lock, which is later acquired by the other thread who can notify this thread. Here is a nice diagram of how the state transition of a thread happens in Java:

wait and notify in Java



5. A thread waiting due to a call to wait() method can wake up either by notification e.g. calling notify() or notifyAll() method on the same object or due to interruption.


6. The wait() method throws InterrruptedException in Java, which is a checked exception. You must provide a handler for this, but it's your choice whether you really want to handle the interruption or not.


7. You must call the wait() method on a shared object like in producer-consumer problem, the task queue is shared between producer and the consumer thread. In order to communicate, you must use that queue on the synchronized block and subsequently called wait() method on queue like queue.wait().

The other thread should also call the notify() or notifyAll() method on same shared object i.e. queue.notify() or queue.notifyAll(). You can also see my post on how to do inter-thread communication in Java for more details.

inter thread communication in Java using wait notify



8. When you call the notify() method on a shared object and if more than one thread is waiting on that lock then anyone of them will get the notification, which thread will get the notification is not guaranteed. If only one thread is waiting then it will get the notification.


9. When you call the notifyAll() method on the shared object and if more than one thread is waiting for notification then all of them will receive the notification but who will get the CPU to start execution is not guaranteed.

It depends on upon thread scheduler. This means it's possible for a thread to get the notification, but it might go to the wait state again if the condition for wait still holds true, mainly due to other thread's processing.

For example, suppose 5 people are waiting for food and they all hear the notification that food has arrived, but only of them goes past the door and eats food. When the next people's chance come to go past the door food is already finished so it goes to the wait state again. 

10. Main difference between notify() and notifyAll() is that in the case of notify() only one of the waiting threads gets a notification but in the case of notifyAll() all threads get a notification. You can also read the real difference between notify() and notifyAll() to learn more


That's all about wait(), notify() and notifyAll() methods in Java. These are three of the most important methods every Java developer should know. It's key to implement inter-thread communication in Java. You should try writing code using the wait() and notify() method by hand or by using a notepad to learn the concept better.

You can also do a couple of exercises to learn the concept of wait and notify better e.g. implementing a bounded buffer in Java or solving the famous producer-consumer problem using wait notify in Java, as shown here.

1 comment:

Feel free to comment, ask questions if you have any doubt.