Make delicious recipes!

Wait, Notify and NotifyAll

Busy Wait : A thread continuously polling to see if it has some task to do is called to be on busy wait. Busy wait can be prevented by using wait/notify(all) from inside a synchronized block.


Example:


// A dummy object.
// Used only for wait/notify purposes.
public class MonitorObject 
{
}


// Class actually using wait/notify
public class MyWaitNotify 
{

    MonitorObject myMonitorObject = new MonitorObject();

    public void doWait() {
        synchronized(myMonitorObject) {
            try{
                myMonitorObject.wait();
            } catch(InterruptedException e) {...}
        }
    }

    public void doNotify() {
        synchronized(myMonitorObject) {
            myMonitorObject.notify();
        }
    }
}


notify wakes-up any one thread waiting on that object.

notifyAll wakes-up all the threads waiting on that object.


All the 3 methods must be called from inside a synchronized block.

But, how is this possible?

Wouldn't the waiting thread keep the lock on the monitor object (myMonitorObject) as long as it is executing inside a synchronized block? Will the waiting thread not block the notifying thread from ever entering the synchronized block in doNotify()?

The answer is no. Once a thread calls wait() it releases the lock it holds on the monitor object before going into wait state. This allows other threads to call wait() or notify() too, since these methods must be called from inside a synchronized block.

Once a thread is awakened it cannot exit the wait() call until the thread calling notify() has left its synchronized block. In other words: The awakened thread must re-obtain the lock on the monitor object before it can exit the wait() call, because the wait call is nested inside a synchronized block. So if multiple threads are awakened using notifyAll() only one awakened thread at a time can exit the wait() method, since each thread must obtain the lock on the monitor object in turn before exiting wait().



Spurious Wakeups

It is possible for a thread to wake-up even without a notify call due to inexplicable reasons.

If such a thing happens, it can devastate the application.

Such a thing can be prevented by using an auxiliary variable to indicate the state of notification.

Example:


Difference between notify() and notifyAll()

notify() causes one thread to wake-up and run while notifyAll() causes all threads to wake-up but since the woken-up threads will need to acquire the lock (as they are inside synchronized block), only one thread will run here too.

Difference between the two is that after notify, only one thread is in non-waiting state, rest all are still waiting. Whereas in notifyAll, all threads come out of the waiting state and do not need another notify or notifyAll call to start them.


Difference between wait, lock and synchronized

Synchronized is same as lock except that it is cleaner but offers less flexibility by blocking access to a critical section of code.

Lock means that only one thread can acquire lock, all other threads calling lock() will block if the lock was already taken by some thread. So synchronized is basically a special form of Lock. With synchronized, you do not have to worry about locks not getting released due to exceptions in critical section.

Wait() means the calling thread goes to waiting state and gives up the lock it’s holding before going to waiting state. When it will come alive, it will first try to acquire the lock it was holding before proceeding ahead. If the current thread does not own the lock on the object on which it called wait, an lllegalMonitorStateException is thrown.


This means that wait can be called only after acquiring lock on an object. Purpose of wait is to allow other threads to enter the critical section (a section guarded by locks) by giving up the lock till notify is called.

That’s why when the waiting thread gets notified, it tries to get the lock before proceeding because the wait call happens in critical region.


So, in summary,

lock/synchronized: Take a lock before proceeding. If lock taken already, wait.

wait: Give up the lock taken already and wait on some object to be notified by some other thread for proceeding.

A thread waiting on a lock is called Blocked

A thread waiting on an object’s monitor (due to wait()) is called Waiting

So, a thread is made to go into ‘blocked’ state due to action of some other thread (which took the lock before this thread). While a thread goes into ‘waiting’ state voluntarily and gives other ‘blocked’ threads a chance to run by releasing the lock.

Aid to remember: Block state happens when attempting to lock (Block and lock rhyme). Waiting state happens when thread itself calls wait (Waiting and wait - same prefix)




Like us on Facebook to remain in touch
with the latest in technology and tutorials!


Got a thought to share or found a
bug in the code?
We'd love to hear from you:

Name:
Email: (Your email is not shared with anybody)
Comment:

Facebook comments:

Site Owner: Sachin Goyal