Java Atomic package dissection

Java provides a set of useful classes in it’s java.util.concurrent.atomic package. This package contains a small toolkit of classes that support lock-free (at least whenever possible) and thread-safe programming on single variables. But how can it be lock-free (or what does that mean)? How useful they are? When to use them?

What is it?

The Java atomic package gives us a set of useful classes. They are a result of an effort to provide developers a set of atomic features for the most common race condition scenarios (check-then-act and read-modify-write). The JVM will try to enforce atomicity of such operations but it depends on the CPU features. By atomic operations I mean lock-free, however, in some CPUs it is still impossible to provide such features (atomicity depends on CPUs providing such features), however the JVM will still provide you a virtual atomic operation (a bit slower than atomic operations).

This atomic operations allows one to avoid synchronized blocks. They also guarantee the memory visibility (like volatil variables), that is, accesses (read/write) are done against the main memory.

The memory effects for accesses and updates of atomics generally follow the rules for volatiles, as stated in section 17.4 of The Java™ Language Specification.

  • get has the memory effects of reading a volatile variable.
  • set has the memory effects of writing (assigning) a volatile variable.
  • lazySet has the memory effects of writing (assigning) a volatile variable except that it permits reorderings with subsequent (but not previous) memory actions that do not themselves impose reordering constraints with ordinary non-volatile writes. Among other usage contexts, lazySet may apply when nulling out, for the sake of garbage collection, a reference that is never accessed again.
  • weakCompareAndSet atomically reads and conditionally writes a variable but does not create any happens-before orderings, so provides no guarantees with respect to previous or subsequent reads and writes of any variables other than the target of the weakCompareAndSet.
  • compareAndSet and all other read-and-update operations such as getAndIncrement have the memory effects of both reading and writing volatile variables.

 

When to use it?

So, from what was said before, we can say that Atomic classes are a good optimisation in terms of process management (no locking) but then they have the requirement of changing the main memory directly. In some scenarios this class is really useful, however not all scenarios are good. Usually, in enterprise applications the time it takes to write to main memory on each computation is expensive when comparing to the memory block flush of synchronized blocks.

Use it with wisely, have in consideration all that has been said. If your computation is only about few variables as your state, Atomic classes are really a good option.

December 21, 2013 Concurrency, Java