Codectionary / Developer documentation / Java

Atomic Variables

Classes like AtomicInteger, AtomicLong, and AtomicBoolean, from java.util.concurrent.atomic, provide thread-safe operations on single variables without needing explicit synchronized blocks. They use low-level, lock-free CPU instructions (compare-and-swap) to guarantee that operations like incrementAndGet() are atomic - performed as a single, uninterruptible step - even when many threads use them concurrently.

Syntax

AtomicInteger counter = new AtomicInteger(0);

Examples

AtomicInteger Basics

Thread-safe increment and decrement without a synchronized block.

import java.util.concurrent.atomic.AtomicInteger;

AtomicInteger counter = new AtomicInteger(0);

counter.incrementAndGet();  // atomically adds 1, returns new value
counter.incrementAndGet();
counter.addAndGet(5);        // atomically adds 5

System.out.println(counter.get());  // 7

Comparing to a Non-Atomic Counter

Why AtomicInteger matters: a plain int shared across threads is not safe to increment without extra synchronization.

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

AtomicInteger safeCounter = new AtomicInteger(0);
ExecutorService executor = Executors.newFixedThreadPool(4);

for (int i = 0; i < 1000; i++) {
    executor.submit(safeCounter::incrementAndGet);
}

executor.shutdown();
// safeCounter will reliably reach 1000 - a plain "int count" shared this way
// could lose increments due to race conditions between threads

compareAndSet()

The atomic building block: only updates the value if it currently matches an expected value.

import java.util.concurrent.atomic.AtomicInteger;

AtomicInteger value = new AtomicInteger(10);

boolean updated = value.compareAndSet(10, 20);  // succeeds: current value was 10
System.out.println(updated);      // true
System.out.println(value.get());   // 20

boolean failed = value.compareAndSet(10, 30);   // fails: current value is now 20, not 10
System.out.println(failed);       // false
System.out.println(value.get());   // still 20

Best practices

  • Use atomic classes instead of a synchronized block when you only need to protect a single variable - they are typically faster due to lock-free implementation
  • Use incrementAndGet()/getAndIncrement() rather than manually reading, adding, and writing back a value across separate atomic operations
  • Reach for a synchronized block or a Lock instead when you need to atomically update more than one related variable together
  • Remember atomic classes only guarantee safety for the operations they provide directly - wrapping several atomic calls together does not make the whole sequence atomic

Runtime & versions

Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

Java Language Specification

Specifications & further reading