Wednesday, November 10, 2021

Why wait(), notify() And notifyAll() Must be Called Inside a Synchronized Method or Block

Why wait(), notify() and notifyAll() methods in Java must be called inside a synchronized method or block is a very frequently asked Java multi-threading interview question. It is very closely related to another multi-threading question Why wait(), notify() and notifyAll() methods are in Object class?

There are few points we should be aware of before going into the reasons for why wait(), notify() and notifyAll() must be called inside a synchronized method or block.

  1. Every object created in Java has one associated monitor (mutually exclusive lock). Only one thread can own a monitor at any given time.
  2. For achieving synchronization in Java this monitor is used. When any thread enters a synchronized method/block it acquires the lock on the specified object. When any thread acquires a lock it is said to have entered the monitor. All other threads which need to execute the same shared piece of code (locked monitor) will be suspended until the thread which initially acquired the lock releases it.
  3. wait method tells the current thread (thread which is executing code inside a synchronized method or block) to give up monitor and go to waiting state.
  4. notify method wakes up a single thread that is waiting on this object's monitor.
  5. notifyAll method wakes up all the threads that called wait() on the same object.

Any method or a block of code, if not qualified with the keyword synchronized can be executed by more than one thread at any given time as object's monitor(lock) is not in the picture. Where as when a method is synchronized (or there is a synchronized block) only a single thread who has acquired the object's monitor can access the code.

I hope you would have got the picture by now. Since wait() method is about thread releasing the object's lock and go to sleep where as notify/notifyAll methods are about notifying the thread(s) waiting for the object's lock. So, wait(), notify() and notifyAll() methods (as mentioned above) should be invoked on an object only when the current thread has already acquired the lock on an object.
In fact not doing so will result in java.lang.IllegalMonitorStateException.

As example suppose I have this code where I have commented the synchronized keyword and trying to call wait

while(true){
    //synchronized (sharedListObj) {
    // While condition as mandated to avoid spurious wakeup
    while(sharedListObj.size() >= 1){
        try {
            sharedListObj.wait();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    // Putting value in the list
    System.out.println("Adding to queue - " + Thread.currentThread().getName() + " " + ++i);
    sharedListObj.add(i);
    //sharedListObj.notify();    
    // To get out of while(true) loop
    if(i > 4) break;
    //}
}

This will throw exception-

Exception in thread "Producer" java.lang.IllegalMonitorStateException
 at java.lang.Object.wait(Native Method)
 at java.lang.Object.wait(Object.java:502)
 at org.netjs.examples.Producer.run(InterThreadDemo.java:20)
 at java.lang.Thread.run(Thread.java:745)

To summarize it, wait() method tells the current thread (thread which is executing code inside a synchronized method or block) to give up monitor. Object's lock is acquired by a thread only when it is executing in a synchronized context. So it makes sense to use wait() method, which asks thread to release the lock, only in synchronized context.

Same way; when object's notify() or notifyAll() method is called, single thread (in case of notify) or all of the threads (in case of notifyAll), waiting for the object's lock change state to runnable and contend for the object's lock, and the thread that gets the lock starts execution. Here again, notify() and notifyAll() methods can inform other threads, that the object's lock can be acquired now, only if these methods are called from the synchronized object.

So these are the reasons Why wait(), notify() And notifyAll() Must be Called Inside a Synchronized Method or Block. Please do share with me if you know any other reason for doing the same.


Related Topics

  1. Thread Priority in Java Multi-Threading
  2. Can we Start The Same Thread Twice in Java
  3. Volatile Keyword in Java With Examples
  4. Is String Thread Safe in Java
  5. Java Multithreading Interview Questions And Answers

You may also like-

  1. Externalizable Interface in Java
  2. covariant return type in Java
  3. interface default methods in Java 8
  4. Lambda Expression Examples in Java
  5. How HashMap Works Internally in Java
  6. equals() And hashCode() Methods in Java
  7. Difference Between Checked And Unchecked Exceptions in Java
  8. Batch Processing in Java JDBC - Insert, Update Queries as a Batch

3 comments:

  1. Thanks for the blog. But I have a doubt.
    If we make an object's method synchronous, does it acquire the lock on the entire object?
    What happens in case of static variables (when I try to make a static variable synchronous/add synchronous level to a block)?

    ReplyDelete
    Replies
    1. Synchronization happens on a single lock associated with the object. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block until the first thread is done with the object.
      Static synchronization happens at the class level so only a single lock is available at the class level instead of at object level. Please refer - Static Synchronization in Java Multi-Threading to know more about static synchronization.

      Delete