How do atomics work?

Let's start by defining what atomics are and why they are needed. Atomic* classes are a family of classes from java.util.concurrent. They provide a set of atomic operations for corresponding types. For example, using the getAndIncrement/incrementAndGet methods of the AtomicInteger class, you can perform an increment (i++) that would not be atomic under normal conditions.

The implementation approaches for most atomic methods can be roughly divided into two groups: compare-and-set and set-and-get.

Compare-and-set methods take the old value and the new value as parameters. If the passed old value matches the current one, the new value is set. They typically delegate calls to methods in the Unsafe class, which are replaced by native implementations in the virtual machine. In most cases, the virtual machine uses the processor's atomic compare-and-swap (CAS) operation. Therefore, atomics are usually more efficient than standard, costly locking mechanisms.

Set-and-get methods deal with cases where the old value is unknown. A small trick is used here: the program first reads the current value and then writes the new value, also using CAS, because the value could change even between these steps. This read-then-write attempt is repeated in a loop until the old value matches and the variable is successfully written.

This trick is called double-checked or optimistic locking and can also be used in user code with any synchronization method. The optimism lies in assuming that there is no race condition, resorting to synchronization only if a race condition does occur. Implementing optimistic locking can be given as a standalone interview task.