Costs of Synchronization
Synchronized areas of code affect performance in two ways. First, the amount of time an ap-
plication spends in a synchronized block affects the scalability of an application. Second, ob-
taining the synchronization lock requires some CPU cycles and hence affects performance.
Synchronization and scalability
First things first: when an application is split up to run on multiple threads, the speedup it
sees is defined by an equation known as Amdahl's law:
P is the amount of the program that is run in parallel, and N is the number of threads utilized
(assuming that each thread always has available CPU). So if 20% of the code exists in serial-
ized blocks (meaning that P is 80%), with eight available CPUs the code can be expected to
run (only) 3.33 times faster.
One key fact about this equation is that as P decreases—that is, as more code is located with-
in serialized blocks—the performance benefit of having multiple threads also decreases. That
is why limiting the amount of code that lies in the serialized block is so important. In this ex-
ample, with eight CPUs available we might have hoped for an eight times increase in speed.
When only 20% of the code is within a serialized block, the benefit of having multiple
threads was reduced by over 50% (i.e., the increase was only 3.3 times).
Costs of locking objects
Aside from its impact on scalability, there are two basic costs to the operation of synchroniz-
First, there is the cost of obtaining the synchronization lock. If a lock is unconten-
ded—meaning that two threads are not attempting to access the lock at the same time—then
this cost is quite minimal. There is a slight difference here between the synchronized
keyword and CAS instructions. Uncontended synchronized locks are known as uninflated
locks, and the cost of obtaining an uninflated lock is on the order of a few hundred nano-
seconds. Uncontended CAS code will see an even smaller performance penalty. (See
Chapter 12 for an example of the difference.)