Back to Atomic Classes & CAS
Q1Question 1 of 4

What is AtomicInteger and CAS?

Key Concepts
  • AtomicInteger provides thread-safe integer operations without locks, using hardware CAS (Compare-And-Swap).
  • CAS is a single CPU instruction (CMPXCHG on x86) that atomically reads, compares, and conditionally writes.
  • incrementAndGet() loops: reads the current value, computes new value, and CAS-writes. If another thread changed it, CAS fails and retries.
  • Lock-free means no thread is ever blocked: no monitor, no deadlock risk, no context switching overhead.
  • Key methods: get(), set(), incrementAndGet(), compareAndSet(), updateAndGet(), addAndGet().
  • Use AtomicInteger for counters and sequence generators; use LongAdder for high-contention scenarios.

Definition

AtomicInteger provides lock-free thread-safe integer operations using hardware CAS, where incrementAndGet() atomically reads, increments, and writes in a retry loop.
  • Lock-free – AtomicInteger never blocks a thread. No monitor lock, no deadlock risk, no context switching. All operations use hardware CAS.
  • CAS (Compare-And-Swap) – a single CPU instruction (CMPXCHG on x86, LDREX/STREX on ARM) that atomically: reads the current value, compares it to an expected value, and if they match, writes the new value.
  • Retry loop – incrementAndGet() reads the current value, computes the new value, and attempts a CAS write. If another thread changed the value between the read and the CAS, the CAS fails and the operation retries with the fresh value.
  • Atomic family – AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference, AtomicIntegerArray, LongAdder, AtomicStampedReference.

A mechanical token dispenser at the bank counter. You press the button and the number advances by 1. Even if 10 people press simultaneously, the mechanism physically ensures each press advances the counter. No lock on the machine. No waiting in line. The hardware resolves collisions internally.

Understanding the Concepts

What is CAS (Compare-And-Swap)?

CAS is a hardware instruction that performs an atomic conditional write. It reads the current value at a memory address, compares it to an expected value, and only writes the new value if they match.

TEXT
CAS(address, expected, new):
  atomically {
    if (memory[address] == expected) {
      memory[address] = new;
      return true;   // success
    } else {
      return false;  // another thread changed it
    }
  }

How does AtomicInteger.incrementAndGet() work?

JAVA
// Simplified from OpenJDK source
public int incrementAndGet() {
    int prev, next;
    do {
        prev = get();                    // step 1: volatile read
        next = prev + 1;                 // step 2: compute new value
    } while (!compareAndSet(prev, next)); // step 3: CAS write
    return next;
    // If another thread changed the value between step 1 and 3,
    // compareAndSet returns false, and the loop retries.
}

What are the key AtomicInteger methods?

JAVA
package com.bank.core;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {
    public static void main(String[] args) {
        AtomicInteger counter = new AtomicInteger(0);

        counter.get();                        // volatile read: 0
        counter.set(100);                     // volatile write
        counter.incrementAndGet();            // ++counter: returns 101
        counter.getAndIncrement();            // counter++: returns 101, now 102
        counter.decrementAndGet();            // --counter: returns 101
        counter.addAndGet(50);                // counter += 50: returns 151
        counter.compareAndSet(151, 200);      // CAS: if 151, set to 200

        // Functional updates (Java 8)
        counter.getAndUpdate(v -> v * 2);     // returns old, sets 400
        counter.updateAndGet(v -> v + 10);    // sets 410, returns new
        counter.accumulateAndGet(5, Integer::sum); // accumulate: 415

        System.out.println("Final: " + counter.get()); // 415
    }
}
TEXT
Final: 415

How does AtomicInteger compare to synchronized?

JAVA
package com.bank.core;

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicVsSyncDemo {
    private final AtomicInteger atomicCount = new AtomicInteger(0);
    private int syncCount = 0;
    private final Object lock = new Object();

    // Lock-free: no blocking, no deadlock, no context switch
    public void atomicIncrement() {
        atomicCount.incrementAndGet();
    }

    // Blocking: monitor acquisition, possible context switch
    public void syncIncrement() {
        synchronized (lock) {
            syncCount++;
        }
    }
}

| Feature | AtomicInteger | synchronized |
|---|---|---|
| Blocking | No (CAS retry) | Yes (monitor lock) |
| Deadlock risk | None | Possible (nested locks) |
| Overhead | CAS instruction | Monitor enter/exit |
| Multi-variable | No | Yes |
| Best for | Single-variable operations | Multi-variable compound ops |

When should you use AtomicInteger?

  • Counters: transaction count, request count, error count.
  • Sequence generators: tradeId = atomicSeq.incrementAndGet().
  • Statistics: tracking maximum via updateAndGet(v -> Math.max(v, newValue)).
  • State machines: state.compareAndSet(PENDING, ACTIVE) for state transitions.

When should you NOT use AtomicInteger?

DIAGRAM
- **Multi-variable invariants**: `low <= high` with two separate AtomicIntegers is not safe. Use synchronized.
- **Check-then-act on different data**: `if (account.balance >= amount) otherAccount.credit(amount)`. Use synchronized.
- **Very high contention (100+ threads)**: CAS retries degrade performance. Use `LongAdder`.

What should a senior engineer know?

  • CAS on x86: LOCK CMPXCHG instruction. The LOCK prefix ensures the cache line is exclusively owned during the operation.
  • False sharing: if two AtomicIntegers are on the same cache line (64 bytes), concurrent CAS operations cause cache line bouncing. Use @Contended annotation or manual padding.
  • ABA problem: CAS checks if the value is the same, but it may have changed from A to B and back to A. Use AtomicStampedReference to detect this.
  • VarHandle (Java 9): AtomicInteger is implemented using VarHandle internally since Java 9, replacing Unsafe.

Visual Overview

DIAGRAM
  CAS Retry Loop (incrementAndGet):

  Thread-1              Thread-2              value
  ─────────             ─────────             ─────
  read: 0                                     0
                        read: 0               0
  CAS(0 -> 1): SUCCESS                       1
                        CAS(0 -> 1): FAIL     1
                        read: 1               1
                        CAS(1 -> 2): SUCCESS  2

  Both increments succeed! No lost updates.
  Lock-free: neither thread was ever blocked.

Key Takeaway

AtomicInteger provides lock-free thread safety using hardware CAS (Compare-And-Swap). The incrementAndGet() method reads the current value, computes the new value, and CAS-writes. If another thread changed the value, CAS fails and the loop retries with the fresh value. This is a single CPU instruction (CMPXCHG on x86), with no monitor lock, no blocking, no deadlock risk.

Use AtomicInteger for single-variable operations: counters, sequence generators, state transitions. Use LongAdder for high-contention counters where CAS retry overhead becomes significant. Use synchronized when you need multi-variable atomicity.

Remember one sentence: AtomicInteger uses hardware CAS to atomically read-modify-write without locks, retrying if another thread changed the value.

---

Share
Use ← → arrow keys to navigate