Category : Java | Sub Category : Java Threads | By Prasad Bonam Last updated: 2021-04-20 09:34:35 Viewed : 407
In multi-threaded environment, the wait(), notify() and notifyAll() methods are used for synchronizing and coordinating the access for the shared resource among threads. These methods should be called in a synchronized context.
wait(), notify() and notifyAll() methods are derived from the Object class. Since these methods are frequently used in multithreaded environments with threads, most of the people have misunderstand that these methods are derived from Thread class. Since it is retrieved from the Object class, any object/instance created in java can be synchronized.
Lets look at a real world example. Here is the code and explanation.
You can see that the Factory class has created and started two thread objects known as Producer and Consumer. Both these thread objects share a common queue for their operations. In last, the main thread wait until the Consumer thread calls the notify() method on the consumer thread itself. Now both thread has been started and lets look at their execution.
The Producer thread is responsible for producing the item and the consumer thread is responsible for consuming the items. As you can see that the business logic of both producer and consumer has been placed in a synchronized blocks. Both synchronized blocks have been synchronized with sharedQueue. Therefore in order to complete their execution, the running thread should have the the object monitor/lock of the sharedQueue.
If the object monitor of the shared queue is first acquired by the Producer thread, the Consumer thread has to wait until it is released by the Producer thread.
If the object monitor of the shared queue is first acquired by the Consumer thread, the Producer thread has to wait until it is released by the Consumer thread.
The producer stores the produced items in the sharedQueue and its max size is considered as 5. when the queue size is become 5, the Producer thread release the object monitor of the sharedQueue and allow any other thread to continue/resume its works with sharedQueue. This is done by calling the notify() method on the sharedQueue.
notify() – notify an already waited thread on sharedQueue about releasing the monitor/lock of the shared queue. Once the notify() is called, it will not release the lock/monitor immediately. it will release the monitor once the synchronized block is completed.
wait() – this will immediately release the object monitor/lock of the shared queue and the currently running thread hold/sleep until some other thread calls the notify method on the same object.
Once Producer thread invokes the wait() on the sharedQueue, the monitor of the shared queue is released and currently running thread (Producer thread) goes to the sleep state. The released monitor/lock of the shared queue is available for some other waiting thread to acquire. In this case, it will be acquired by the Consumer thread.
Now the Producer thread is waiting until some other thread calls the notify(() method and release the monitor of the sharedQueue. Consumer thread has acquired the monitor and continue its work with it.
The Consumer thread will again consumes all the items in the queue until the queue is empty. when the queue is empty, it invokes the notify() method on the sharedQueue to notify one of the waiting thread about releasing the object monitor. Now the producer thread is aware and ready to acquire the object monitor once it is released by the Consumer thread. Consumer thread will invoke wait() method for waiting until producer produced items and calls the notify() on the sharedQueue.
The access for the sharedQueue will be properly synchronized between Producer and Consumer until both of thread completes their execution. once the execution is over, each method will call their notify methods to release their object monitor and acknowledge some other threads that are waiting on them.
Can you remind that the main thread is waiting for the Consumer thread. so once the notify method of the Consumer thread is invoked, the main thread will be resumed.
You can run the program and see the output as follows.
factory started producing item 10 producing item 9 producing item 8 producing item 7 producing item 6 queue is full. notifying the consumer main thread wait until the consumer completes consumer started consuming item 10 consuming item 9 consuming item 8 consuming item 7 consuming item 6 consumer waits till producer produces items producing item 5 producing item 4 producing item 3 producing item 2 producing item 1 queue is full. notifying the consumer consuming item 5 consuming item 4 consuming item 3 consuming item 2 consuming item 1 consumer waits till producer produces items Producer Completed (Nothing to be produced) : remaining items [0] Consumer Completed (Nothing to be consumed) : remaining items [0] main thread completed
Now lets look at the functionality of each method.
if the wait() is called on a object, the currently running thread will release the monitor/lock of that object and go to sleep until some other thread calls the notify() method on the same object.
e.g: –
synchronized(objectA){ objectA.wait(); }
The currently running thread will release the monitor of the objectA and go to sleep until some other thread invokes the notify() or notifyAll() method on the objectA.
It wakes up one single thread that called wait() on the same object. It should be noted that calling notify() does not actually give up a lock on a resource. It tells a waiting thread that that thread can wake up. However, the lock is not actually given up until the notifier’s synchronized block has completed. The selection of the notifying thread will be decided by the thread scheduler.
notifyAll()
It wakes up all the threads that called wait() on the same object. The highest priority thread will run first in most of the situation, though not guaranteed.
Important
if the wait() and notify()/notifyAll() are used together, the best way to call the notify()/notifyAll() first and then wait() method. if the notify() is called after the wait() method, then the notify() will not be invoked because the currently running thread will go to the sleep state immediately.