Threads of Control |
Theget()
andput()
methods in the CubbyHole object both make use of thenotify()
andwait()
methods to coordinate getting and putting values into the CubbyHole. Bothnotify()
andwait()
are members of the java.lang.Object class.
Note: Thenotify()
andwait()
methods can be invoked only from within a synchronized method or within a synchronized block or statement.
Let's investigate CubbyHole's use of the
notify()
method by looking at theget()
method.The notify() method
Theget()
method callsnotify()
as the last thing it does (besides return). Thenotify()
method chooses one thread that is waiting on the monitor held by the current thread and wakes it up. Typically, the waiting thread will grab the monitor and proceed.In the case of the Producer/Consumer example, the Consumer thread calls the
get()
method, so the Consumer thread holds the monitor for the CubbyHole during the execution ofget()
. At the end of theget()
method, the call tonotify()
wakes up the Producer thread that is waiting to get the CubbyHole's monitor. Now, the Producer thread can get the CubbyHole monitor and proceed.If multiple threads are waiting for a monitor, the Java runtime system chooses one of the waiting threads, making no commitments or guarantees about which thread will be chosen.public synchronized int get() { while (available == false) { try { wait(); } catch (InterruptedException e) { } } available = false; notify(); // notifies Producer return contents; }The
put()
method works in a similar fashion toget()
, waking up the Consumer thread that is waiting for the Producer to release the monitor.The Object class has another method--
notifyAll()
--that wakes up all the threads waiting on the same monitor. In this situation, the awakened threads compete for the monitor. One thread gets the monitor and the others go back to waiting.The wait() method
Thewait()
method causes the current thread to wait (possibly forever) until another thread notifies it of a condition change. You usewait()
in conjunction withnotify()
to coordinate the activities of multiple threads using the same resources.The
get()
method contains awhile
statement that loops untilavailable
becomestrue
. Ifavailable
is false--the Producer has not yet produced a new number and the Consumer should wait--theget()
method callswait()
.The
while
loop contains the call towait()
. Thewait()
method waits indefinitely for a notification from the Producer thread. When theput()
method callsnotify()
, the Consumer wakes up from the wait state and continues within the while loop. Presumably, the Producer has generated a new number and theget()
method drops out of the while loop and proceeds. If the Prodcuer had not generated a number,get()
goes back to the beginning of the loop and continues to wait until the Producer generates a new number and callsnotify()
.public synchronized int get() { while (available == false) { try { wait(); // waits for notify() call from Producer } catch (InterruptedException e) { } } available = false; notify(); return contents; }The
put()
method works in a similar fashion, waiting for the Consumer thread to consume the current value before allowing the Producer to produce a new one.Besides the version used in the Producer/Consumer example, which waits indefinitely for notification, the Object class contains two other versions of the
wait()
method:
wait(long timeout)
- waits for notification or until the timeout period has elapsed--timeout is measured in milliseconds.
wait(long timeout, int nanos)
- waits for notification or until
timeout
milliseconds plus nanos nanoseconds have elapsed.Monitors and the notify() and wait() Methods
You might have noticed a potential problem in CubbyHole'sput()
andget()
methods. At the beginning of theget()
method, if the value in the CubbyHole is not available (that is, the Producer has not generated a new number since the last time the Consumer consumed it), then the Consumer waits for the Producer to put a new value into the CubbyHole. So, the question arises--how can the Producer put a new value into the CubbyHole if the Consumer holds the monitor? (The Consumer holds the CubbyHole's monitor because it's within the synchronized methodget()
.)Similarly, at the beginning of the
put()
method, if the value in the CubbyHole has not yet been consumed, then the Producer waits for the Consumer to consume the value in the CubbyHole. And again the question arises--how can the Consumer consume the value in the CubbyHole, if the Producer holds the monitor? (The Producer holds the CubbyHole's monitor because it's within the synchronized methodput()
.)Well, the designers of the Java language thought of this too. When the thread enters the
wait()
method, which happens at the beginning of both theput()
andget
methods, the monitor is released atomically, and when the thread exits thewait()
method, the monitor is acquired again. This gives the waiting object the opportunity to acquire the monitor and, depending on who's waiting, consume the value in the CubbyHole or produce a new value for the CubbyHole.
Threads of Control |