Java Atomic Variables

Java atomic variables provide thread-safe operations on shared values without requiring an explicit mutual-exclusion lock. They are useful when an operation can be expressed as an atomic read-modify-write such as incrementing a counter or conditionally updating a value.

The `java.util.concurrent.atomic` package provides classes such as `AtomicInteger`, `AtomicLong`, `AtomicBoolean`, and `AtomicReference`. Their operations are designed for safe concurrent access to a single shared value.

A key benefit is that compound operations can be performed atomically. For example, `incrementAndGet()` prevents two threads from losing an increment in the way that can happen with a plain `count++`, because the read, modification, and write are treated as one atomic operation.

Many atomic operations use compare-and-set (CAS). CAS checks whether the current value is the expected value and, if so, replaces it with a new value as one atomic operation. If another thread changed the value first, the CAS fails and code can retry or take another action.

Atomic variables provide visibility and atomicity guarantees appropriate for their operations, but they do not automatically make larger multi-variable invariants thread-safe. If several pieces of state must change together, a lock or another coordination mechanism may be more appropriate.

Atomic classes are particularly useful for counters, flags, sequence numbers, statistics, and other small shared state. They should not be treated as a universal replacement for `synchronized` or `Lock`, especially when a critical section contains multiple dependent operations.

Key points

Interview questions

Does an atomic variable guarantee that a whole object is thread-safe?

No. Atomicity applies to the operations supplied by the atomic variable, not automatically to every operation involving the surrounding object. If an object has multiple fields that must change together, independent atomic variables may still allow an inconsistent combination. A lock or another higher-level synchronization strategy may be needed to preserve the invariant.

Why would you use `AtomicInteger` instead of an `int` for a shared counter?

A plain `int` does not make a compound operation such as `count++` atomic between threads. `AtomicInteger` provides operations such as `incrementAndGet()` that perform the update atomically. This prevents lost updates when multiple threads increment the same counter concurrently.

What is compare-and-set (CAS)?

CAS compares the current value with an expected value and changes it only if they match. The comparison and update occur as one atomic operation. If another thread changed the value first, the CAS fails, allowing the caller to retry or handle the conflict.

How is `AtomicInteger` different from `volatile int`?

Both can provide visibility of updates between threads, but they offer different operation sets. `volatile int` does not make a compound expression such as `value++` atomic. `AtomicInteger` provides atomic read-modify-write operations such as `incrementAndGet()` and `compareAndSet()`.

When would you choose a lock instead of an atomic variable?

I would use a lock when the operation requires coordinating multiple fields, enforcing a complex invariant, or performing several steps that must appear as one critical section. An atomic variable is a good fit when the shared state and required transition can be represented by a supported atomic operation. The choice should be based on the synchronization semantics required by the algorithm rather than assuming lock-free code is always preferable.