THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

Here is a method to replace each element in an array with its absolute value, relying on a synchronized
statement to control access to the array:


/* make all elements in the array non-negative /
public static void abs(int[] values) {
synchronized (values) {
for (int i = 0; i < values.length; i++) {
if (values[i] < 0)
values[i] = -values[i];
}
}
}


The values array contains the elements to be modified. We synchronize values by naming it as the object
of the synchronized statement. Now the loop can proceed, guaranteed that the array is not changed during
execution by any other code that is similarly synchronized on the values array. This is an example of what
is generally termed client-side synchronizationall the clients using the shared object (in this case the array)
agree to synchronize on that object before manipulating it. For objects such as arrays, this is the only way to
protect them when they can be shared directly, since they have no methods that can be synchronized.


The synchronized statement has a number of uses and advantages over a synchronized method. First, it
can define a synchronized region of code that is smaller than a method. Synchronization affects
performancewhile one thread has a lock another thread can't get itand a general rule of concurrent
programming is to hold locks for as short a period as possible. Using a synchronized statement, you can
choose to hold a lock only when it is absolutely neededfor example, a method that performs a complex
calculation and then assigns the result to a field often needs to protect only the actual field assignment not the
calculation process.


Second, synchronized statements allow you to synchronize on objects other than this, allowing a
number of different synchronization designs to be implemented. Sometimes you want to increase the
concurrency level of a class by using a finer granularity of locking. It may be that different groups of methods
within a class act on different data within that class, and so while mutual exclusion is needed within a group,
it is not needed between groups. Instead of making all the methods synchronized, you can define separate
objects to be used as locks for each such group and have the methods use synchronized statements with
the appropriate lock object. For example:


class SeparateGroups {
private double aVal = 0.0;
private double bVal = 1.1;
protected final Object lockA = new Object();
protected final Object lockB = new Object();


public double getA() {
synchronized (lockA) {
return aVal;
}
}
public void setA(double val) {
synchronized (lockA) {
aVal = val;
}
}
public double getB() {
synchronized (lockB) {
return bVal;
}
}
public void setB(double val) {

Free download pdf