img
. . . .
Implementing a condition variable in Java is not particularly difficult, but there are a few subtle
nuances (Code Example 6-20). The ConditionVar class itself requires just two methods,
condWait() [equivalent to Java's wait()] and condSignal() [Java's notify()]. [Adding
notifyAll() and a timed wait() is a simple exercise left to the reader.] The subtleties are in
the condWait() method. The mutex must be released and the thread sent to sleep atomically
with respect to the condSignal(), hence the synchronized section.
Consider what would happen if these were not done atomically. With a bit of (bad) luck, thread 1
could call condWait(), release the mutex, and at just that instant thread 2 could be running on a
different CPU. Thread 2 could then lock the mutex, change the condition to true, and call
condSignal(). Thread 1 would not yet be asleep, so it wouldn't be awakened. It would
subsequently go to sleep even though the condition is now true, and the wakeup from thread 2
would be lost. Having done its work, thread 2 might never send another wakeup (it might be
waiting for thread 1 to finish!) and the entire program would hang. This would be a bad thing. It's
known as the "lost wakeup problem" (see The Lost Wakeup).
Example 6-20 Implementing Condition Variables in Java
// Don't use this code, it ignores exceptions.
public class ConditionVar {
public void condWait(Mutex mutex) {
try {
synchronized (this){
mutex.unlock();
wait();
}
} catch (InterruptedException ie) {
// Ignore for now
} finally {
mutex.lock();
}
// *Always* lock before returning!
}
public synchronized void condSignal() {
notify();
}
}
The synchronized section in condWait() does not include the relocking of the mutex. This is
also essential. Consider what could happen if it did (Code Example 6-21).
Example 6-21 condWait() Done Wrong
public void condWait(Mutex mutex) throws InterruptedException {
synchronized (this) {
mutex.unlock();
wait();
mutex.lock();
}
}
Running the producer/consumer code shown in Code Example 6-22, thread 1 might call
condWait(), release the mutex, and go to sleep. Thread 2 could then lock the mutex and call
condSignal(), waking up thread 1. Thread 1 could then reacquire the synchronized section for
the condition variable and call mutex.lock(). At this time, thread 2 has released the mutex,
hurried back to the top, and relocked that mutex. Thread 1 would have to go to sleep to wait for
thread 2 to release it. Thread 2, however, needs to call condSignal() before it releases the
Search WWH :
Custom Search
Previous Page
Multithreaded Programming with JAVA - Topic Index
Next Page
Multithreaded Programming with JAVA - Bookmarks
Home