Skip to content

Atomic Operations

In addition to providing low-level locks and concurrent collections, Java's java.util.concurrent package also includes a set of atomic operation wrapper classes located in the java.util.concurrent.atomic package.

Using AtomicInteger as an example, the main operations it provides are:

  • Increment by a specified value and return the new value: int addAndGet(int delta)
  • Increment by 1 and return the new value: int incrementAndGet()
  • Get the current value: int get()
  • Set a value using Compare-and-Swap (CAS): boolean compareAndSet(int expect, int update)

The atomic classes achieve thread-safe access using a lock-free approach. The core principle behind this is CAS (Compare and Set).

How CAS Works

If we were to implement incrementAndGet() using CAS manually, it might look something like this:

java
public int incrementAndGet(AtomicInteger var) {
    int prev, next;
    do {
        prev = var.get();
        next = prev + 1;
    } while (!var.compareAndSet(prev, next));
    return next;
}

In this code, CAS checks if the current value of AtomicInteger is prev. If it is, the value is updated to next, and the operation returns true. If the current value is not prev, nothing happens, and the operation returns false. By using CAS with a do ... while loop, even if other threads modify the value of AtomicInteger, the final result remains correct.

Example: Generating Unique IDs

Using AtomicLong, we can implement a thread-safe global unique ID generator:

java
class IdGenerator {
    AtomicLong var = new AtomicLong(0);

    public long getNextId() {
        return var.incrementAndGet();
    }
}

Usually, we don't need to use do ... while loops and compareAndSet directly for complex concurrent operations. Instead, we can use built-in methods like incrementAndGet(), making it easy to work with atomic classes.

Advanced Atomic Operations: LongAdder and LongAccumulator

In high contention scenarios, Java 8 introduced LongAdder and LongAccumulator for better performance. These classes are optimized for situations where there are frequent updates, such as counters and accumulators.

Summary

Using atomic operations provided by java.util.concurrent.atomic simplifies multithreading programming:

  • Atomic operations implement thread safety without using locks.
  • Suitable for scenarios like counters and accumulators.
Atomic Operations has loaded