Java Reference
In-Depth Information
The major difference between calling
sleep()
and calling
wait()
is that
wait()
releases any objects
on which the current thread has a lock, whereas
sleep()
does not. It is essential that
wait()
should
work this way, otherwise there would be no way for another thread to change things so that the
condition required by the current thread is met.
Thus the typical use of
wait()
is:
synchronized(anObject) {
while(condition-not-met)
anObject.wait();
// Condition is met so continue...
}
Here the thread will suspend operation when the
wait()
method is called until some other thread
synchronized on the same object calls
notify()
(or more typically
notifyAll()
). This allows the
while
loop to continue and check the condition again. Of course, it may still not be met, in which case
the
wait()
method will be called again so another thread can operate on
anObject
. You can see
from this that
wait()
is not just for getting access to an object. It is intended to allow other threads
access until some condition has been met. You could even arrange that a thread would not continue
until a given number of other threads had called
notify()
on the object to ensure that a minimum
number of operations had been carried out.
It is generally better to use
notifyAll()
rather than
notify()
when you have more than two
threads synchronized on an object. If you call
notify()
when there are two or more other threads
suspended having called
wait()
, only one of the threads will be started, but you have no control over
which it is. This opens the possibility that the thread that is started calls
wait()
again because the
condition it requires is not fulfilled. This will leave all the threads waiting for each other, with no
possibility of continuing.
Although the action of each of these methods is quite simple, applying them can become very complex.
You have the potential for multiple threads to be interacting through several objects with
synchronized
methods and code blocks. We'll just explore the basics by seeing how we can use
wait()
and
notifyAll()
to get rid of a couple of the
while
loops we had in the last example.
Using wait() and notifyAll() in the Bank Program
In the
for
loop in
main()
that generates the transactions and passes them to the
Clerk
objects, we
have two
while
loops that call the
isBusy()
method for a
Clerk
object. These were needed so that
we didn't pass a transaction to a clerk while the clerk was still busy. By altering the
Clerk
class, so that
it can use
wait()
and
notifyAll()
, we can eliminate the need for these.
Try It Out - Slimming Down the Transactions Loop
We want to make the
doTransaction()
method in the
Clerk
class conscious of the state of the
inTray
for the current object. If it is not
null
, we want the method to wait until it becomes so. To use
wait()
the block or method must be synchronized on an object - in this case the
Clerk
object since
inTray
is what we are interested in. We can do this by making the method synchronized:
public class Clerk implements Runnable {
private Bank theBank; // The employer - an electronic marvel