volatile and atomic variables often seem similar at first glance, but they serve different purposes and offer different guarantees in Java concurrency.
🧠 Short Answer:
| Feature | volatile | Atomic variables (AtomicInteger, etc.) |
|---|---|---|
| Guarantees | Visibility only | Visibility + Atomicity |
| Atomic operations? | ❌ No | ✅ Yes |
| Use for increment? | ❌ Not safe | ✅ Safe (e.g., incrementAndGet()) |
| Use case | Flags, simple single-writer variables | Counters, accumulators, CAS-style logic |
| Thread-safe updates | ❌ No | ✅ Yes |
📘 volatile — Visibility Guarantee
Declaring a variable volatile ensures that:
- All threads always see the latest value.
- Writes go directly to main memory, and reads always come from main memory.
BUT:
❗
volatiledoes not make operations atomic — e.g.,++xis not thread-safe!
Example — ❌ Broken counter with volatile
volatile int count = 0;
public void increment() {
count++; // Not atomic: read-modify-write
}
Multiple threads calling increment() can lead to lost updates.
🔐 Atomic Variables (e.g., AtomicInteger)
These are part of java.util.concurrent.atomic and provide:
- Atomic read-modify-write operations
- Internally use low-level CAS (Compare-And-Swap) operations
- Extremely efficient and lock-free
Example — ✅ Safe counter with AtomicInteger
AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // atomic
}
This is thread-safe and lock-free.
🔍 Why Atomic* Is Better for Shared Counters
Let’s say 3 threads try to increment a counter:
- With
volatile, one might read5, increment to6, and write6, even though others have already made it7or8. - With
AtomicInteger, it’ll internally retry using CAS until the increment is successful.
📦 When to Use What?
| Use Case | Best Tool |
|---|---|
| Stop signal or flag | volatile |
| Status monitoring (no increments) | volatile |
| Shared counter, sequence number | AtomicInteger |
| Lock-free algorithms | Atomic* types |
Compound operations (x += y) | Atomic* or synchronized |
🧠 Summary
volatile: Great for simple flags and ensuring visibility.Atomic variables: Best for safe concurrent updates to counters or shared data.- If you need atomicity, use
Atomic*orsynchronized.