Reputation: 833
According to a colleague, JVM does not guarantee that when calling "notify" on an object, the correct "wait" will be notified at that time. He says there can be a case when a previous notify which is not valid anymore is delivered at an invalid time.
Is this true? If so, how/why is this, and what use is the wait/notify mechanism if you cannot assume something as basic as this will work?
Upvotes: 3
Views: 1154
Reputation: 14863
For java.lang.Object.notify, The Javadoc says:
Wakes up a single thread that is waiting on this object's monitor. If any threads are waiting on this object, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.
Here is a pattern to wait for a particular condition:
synchronized( lock ) {
while( conditionEvaluation( data )) {
lock.wait();
}
}
The counterpart should use java.lang.Object.notifyAll()
to ensure the vivacity of the application. Even if today, it's only one waiter, after many evolutions of the software, it may be several waiters in the future, so notifyAll()
is more robust than notify()
.
Upvotes: 2
Reputation: 13535
No it's not true. When a thread invokes notify, one waiting thread is awakened (if such a thread exists, otherwise notification is lost). Probably your colleague had in mind "spurious notify", which can awake a thread when in fact no other thread invoked notify
or notifyAll
. To filter "spurious notify", each notify
invocation should accompanied with some change in monitored object state, and the waiting threads should check that state:
synchronized void up() {
counter++;
notify();
}
synchronized void down() {
while (counter==0) {
wait();
}
counter--;
}
Note checking state in down()
is done before call to wait(), as it could be changed before the invocation and the notification is lost. In other words, the real information is passed with object's state, and wait/notify only help to avoid polling. Never rely on notifications without changing an object's state.
Upvotes: 1
Reputation: 2322
Each object that waits on an intrinsic lock will enter the lock's wait set. When you invoke notify on the lock object, one of the threads in its wait set will be chosen to resume work. The only guarantee that the JVM offers is that the waiting threads will be eventually notified. One of the main reasons for this non-deterministic behavior is the way suspended threads are chosen to run by the JVM, which is arbitrary. In addition however, locks in java implement a non-fair locking policy which permits thread barging. This simply means that it is permissible for new lock requests to jump ahead of the lock's wait set, it the lock is available at the time of the request. The justification behind this is that given substantial contention, there might be some (potentially significant) delay before choosing and resuming a suspended thread in the wait set and the time it actually runs. Any incoming lock request from a thread could therefore utilize this time delay to immediately run, in the hope that it will have released the lock by the time the resumed thread is ready to run. For example consider the following sequence of events:
It should be evident that between step 2 and 6 there exists some time interval where no threads are actually using the lock. Thread C barges in and utilizes the time interval as an optimization. The downside of this of course is the risk of not releasing the lock at the time thread B is ready to run, which at that time thread B will notice that the lock is unavailable and will enter the wait set again. Statistically however it can be proven that non-fair locking offers better performance in most situations.
As an aside note, you could use fair locks where waiting threads are resumed in the order they acquired the lock, but in practice this offers worse performance. Read more about this here: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html
I hope this answers your question.
Upvotes: 2