Wednesday, October 9, 2013

WAIT() NOTIFY() SHORTCOMING: SINGLE WAIT QUEUE

There is an inherent drawback of wait(), notify() methods in Java.
As we are aware every Object in Java is associated with a Entry Queue and a Wait Queue. When a thread reaches a synchronized block, it will wait on the Entry Queue of the Object if any other Thread already has the lock. Once it acquires the lock, does its processing, calles Object.wait(), it waits on Wait Queue of the Object. When some other Thread calls Object.notify(), one of the threads waiting on the Wait Queue is moved to the Entry queue of the Object, where it fights for the lock on the Object (with all other Threads waiting at the Entry Queue).
The shortcoming is that wait is not a conditional wait. Every object has just one wait queue.
So if a Object.notify() is called, of all threads waiting on wait queue, any one thread at random is moved to the entry queue. There is no direct way to notify a particular Thread. What we do is a workaround. Instead of Object.notify(), we call Object.notifyAll(), so as all threads are moved from Object’s wait queue to entry queue. Object.wait() call is made in a while loop each checking on a particular condition. So we attach each Object.wait() with a particular condition, as below.
1
2
3
4
5
6
7
8
9
10
11
12
13
//Thread1
synchronized(object) {
    while(!condition1) {
        object.wait();
    }
}
//Thread 2
synchronized(object) {
    while(!condition2) {
        object.wait();
    }
}
When some other Thread sets condition2 = true (while condition1 is still false) and calls object.nofityAll(), both the above Threads which are waiting on the wait queue of the object, are moved to entry queue of the object. Since wait() is in spinning while loop, so Thread1 (if it gets the lock) again calls object.wait() while the Thread2 (if it gets the lock) comes out of the loop starts the processing.
The drawback you see, is unnecessary processing (looping once and checking for condition) in Thread1 and also unnecessary moving of Thread1 from wait queue of Object to entry queue to back. Thread1 wanted to awaken only ifcondition1 == true and Object.notify() is called (not just @ Object.notify()). What would have been nice if there was provision for Conditional Monitor Objects with each having its own wait queue. Something like,
1
2
3
4
5
6
7
8
9
//Thread 1
synchronized(object) {
    object.wait(condition1);
}
//Thread 2
synchronized(object) {
    object.wait(condition2);
}
Here wait is now waiting on a condition. I have seen some good implementations which are provided  for above problem. One being here.