Java Reference
In-Depth Information
Contended constructs are more expensive. When a second thread attempts to access a syn-
chronized lock, the lock becomes (predictably) inflated. This cost is fixed; the same amount
of code is executed whether there are 2 or 20 threads attempting to access the same lock. (All
20 threads must execute the locking code, of course, so the cost does increase based on the
number of threads—the point is that it is fixed on a per-thread basis).
The cost for a contended operation in code using CAS instructions is unpredictable. CAS
primitives are based on an optimistic strategy: the thread sets a value, executes some code,
and then makes sure that the initial value has not changed. If it has, then the CAS-based code
must execute the code again. In the worst case, this means that two threads could run into an
infinite loop as each modifies the CAS-protected value, only to see that the other thread has
modified it simultaneously. In practice, two threads are not going to get into an infinite loop
like that, but as the number of threads contending for the CAS-based value increase, the
number of retries increases. (If the operations here are read-only, then CAS-based protection
is not affected by contended access. For example, any number of threads may call the Atom-
icLong.get() method on the same object at the same time without paying any penalty for
contention. This is another significant advantage to using CAS-based utilities.)
The second cost of synchronization is specific to Java and depends on the Java Memory
Model. Java, unlike languages such as C++ and C, has a strict guarantee about the memory
semantics around synchronization, and the guarantee applies to CAS-based protection, to tra-
ditional synchronization, and to the volatile keyword.
Search WWH ::

Custom Search