needed. In the case of operations on multiple objects, where could you put a synchronized method?
In these situations, the ability to use client-side synchronization through synchronized statements is often
the only practical approach. An object can have its lock acquired, which prevents any of its synchronized
methods from being invoked except by the lock holder performing the series of invocations. Similarly, you
can acquire the locks of each of the objects involved and then invoke the series of methods on those
objectsbut watch out for deadlock (see Section 14.7 on page 362). As long as the object's methods are already
synchronized on the current object's lock, then other clients of the object need not use client-side
synchronization.
The way that synchronization is enforced in a class is an implementation detail. The fact that it is enforced is
an important part of the contract of the class and must be clearly documentedthe presence of the
synchronized modifier on a method might only be an implementation detail of the class, not part of a
binding contract. Additionally, the synchronization mechanism used within a class may need to be
documented and made accessible to users of the class and/or to extended classes. An extended class needs to
adhere to the synchronization policy enforced by its superclass and it can do that only if the programmer
knows what that policy is and has access to the mechanisms that enforce it. For example, a class that uses a
private field as a lock object prevents an extended class from using the same synchronization mechanismthe
extended class would have to define its own lock object (perhaps this) and override every method of the
superclass to use this new synchronization mechanism. Users of a class may need to know what
synchronization mechanism is used so that they can safely apply client-side synchronization to invoke
multiple methods on an object, without needing all users of that object to apply client-side synchronization.
Exercise 14.3: Write a class whose objects hold a current value and have a method that will add to that value,
printing the new value. Write a program that creates such an object, creates multiple threads, and invokes the
adding method repeatedly from each thread. Write the class so that no addition can be lost.
Exercise 14.4: Modify your code from Exercise 14.3 to use static data and methods.
Exercise 14.5: Modify your code from Exercise 14.4 so that threads can safely decrement the value without
using a static synchronized method.
14.4. wait, notifyAll, and notify
The synchronized locking mechanism suffices for keeping threads from interfering with each other, but
you also need a way to communicate between threads. For this purpose, the wait method lets one thread wait
until some condition occurs, and the notification methods notifyAll and notify tell waiting threads that
something has occurred that might satisfy that condition. The wait and notification methods are defined in
class Object and are inherited by all classes. They apply to particular objects, just as locks do.
There is a standard pattern that is important to use with wait and notification. The thread waiting for a
condition should always do something like this:
synchronized void doWhenCondition() {
while (!condition)
wait();
... Do what must be done when the condition is true ...
}
A number of things are going on here: