1. Avoiding contention for synchronized objects is a useful way to mitigate their per-
2. Thread-local variables are never subject to contention; they are ideal for holding
synchronized objects that don't actually need to be shared between threads.
3. CAS-based utilities are a way to avoid traditional synchronization for objects that
do need to be shared.
One little-discussed performance implication of synchronization involves false sharing. That
used to be a fairly obscure artifact of threaded programs, but as multicore machines become
the norm—and as other, more obvious, synchronization performance issues are ad-
dressed—false sharing is an increasingly important issue.
False sharing occurs because of the way in which CPUs handle their cache. Consider the data
in this simple class:
long l1 ;
long l2 ;
long l3 ;
long l4 ;
Each of the long values here is stored in memory adjacent to one another; for example, l1
could be stored at memory location 0xF20. Then l2 would be stored in memory at 0xF28, l3
at 0xF2C, and so on. When it comes time for the program to operate on l2 , it will load a rel-
atively large amount of memory—for example, 128 bytes from location 0xF00 to
0xF80—into a cache line on one of the cores of (one of) the CPU(s). A second thread that
wants to operate on l3 will load that same chunk of memory into a cache line on a different
Loading nearby values like that makes sense in most cases: if the application accesses one
particular instance variable in an object, it is likely to access nearby instance variables. If