Java Reference
In-Depth Information
public
public String toString () {
NumberFormat nf = nfLocal . get ();
nf . format (...);
}
}
By using a thread-local variable, the total number of objects is limited (minimizing the effect
on GC), and each object will never be subject to thread contention.
The second way to avoid synchronization is to use CAS-based alternatives. In some sense
this isn't avoiding synchronization as much as solving the problem differently. But in this
context, reducing the penalty for synchronization, it works out to have the same effect.
The difference in performance between CAS-based protections and traditional synchroniza-
tion seems like the ideal case to employ a microbenchmark: it should be trivial to write code
that compares a CAS-based operation with a traditional synchronized method. For example,
the JDK provides a simple way to keep a counter using CAS-based protection: the Atom-
icLong and similar classes. A microbenchmark could then compare code that uses CAS-
based protection to traditional synchronization. For example, consider the following:
AtomicLong al = new
new AtomicLong ( 0 );
public
public long
long doOperation () {
return
return al . getAndIncrement ();
}
That code could be compared to this:
private
private volatile
volatile long
long al = 0 ;
public
public synchronized
synchronized doOperation () {
return
return al ++;
}
This turns out to be impossible to measure with a microbenchmark. If there is a single thread
(so there is no possibility of contention), then the microbenchmark using this code can pro-
duce a reasonable estimate of the cost of using the two approaches in an uncontended envir-
onment (and the result of that test is cited in Chapter 12 ) . But that doesn't provide any in-
formation about what happens in a contended environment (and if the code won't ever be
contended, then it doesn't need to be thread-safe in the first place).
Search WWH ::




Custom Search