THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

synchronized (lockB) {
bVal = val;
}
}
public void reset() {
synchronized (lockA) {
synchronized (lockB) {
aVal = bVal = 0.0;
}
}
}
}


The two lock references are protected so that an extended class can correctly synchronize its own
methodssuch as a method to set aVal and bVal to the same value. Also notice how reset acquires both
locks before modifying both values.


Another common use of the synchronized statement is for an inner object to synchronize on its enclosing
object:


public class Outer {
private int data;
// ...


private class Inner {
void setOuterData() {
synchronized (Outer.this) {
data = 12;
}
}
}
}


Like any other object, an inner object is independently synchronizedacquiring the lock of an inner object has
no effect on its enclosing object's lock, nor does acquiring the lock of an enclosing object affect any enclosed
inner objects. An inner class that needs to synchronize with its enclosing object must do so explicitly and a
synchronized statement is a perfect toolthe alternative is to declare a synchronized method in the
enclosing class just for the inner class to use.


If you need a synchronized statement to use the same lock used by static synchronized methods, you can
use the class literal for your class (see example below). This also applies if you need to protect access to static
data from within non-static code. For example, consider the Body class. It maintains a static field, nextID,
to hold the next identifier for a new Body object. That field is accessed in the Body class's no-arg
constructor. If Body objects were created concurrently, interference could occur when the nextID field is
updated. To prevent that from happening you can use a synchronized statement within the Body
constructor that uses the lock of the Body.class object:


Body() {
synchronized (Body.class) {
idNum = nextID++;
}
}

Free download pdf