Absolutely. The key idea is:
volatilegives visibility, but NOT atomicity.
Let's use a simple Java example.
1. volatile boolean running
volatile boolean running = true;Suppose we have two threads:
Thread 1 Thread 2
-------- --------
running = false --------> while (running) {
// sees false
}Because running is volatile, when Thread 1 changes it, Thread 2 is guaranteed to see the latest value.
So:
running = false;is effectively safe for a simple read/write flag.
2. But count++ is different
Consider:
volatile int count = 0;You might think:
count++;is safe because count is volatile.
It isn't.
Why?
Because:
count++;is actually three operations:
1. READ count
2. ADD 1
3. WRITE countEquivalent to:
int temp = count; // READ
temp = temp + 1; // MODIFY
count = temp; // WRITE3. Two threads cause the problem
Suppose:
volatile int count = 0;Two threads both execute:
count++;You might expect:
Thread 1: count++
Thread 2: count++
Final count = 2But this can happen:
Initial count = 0
Thread 1 Thread 2
-------- --------
READ count → 0
READ count → 0
ADD 1 → 1
ADD 1 → 1
WRITE count → 1
WRITE count → 1
Final count = 1 ❌Both threads saw the latest value at the time they read it, but they both read the same value 0.
The second write overwrites the first write.
This is called a lost update.
4. So what exactly does volatile guarantee?
Think of volatile as:
volatile
│
┌────────┴────────┐
↓ ↓
Visibility Ordering
│
↓
Other threads can
see the latest writeBut it does NOT turn a multi-step operation into one indivisible operation.
volatile count
READ ──→ MODIFY ──→ WRITE
↑ ↑
└──── other thread can interfere5. Compare these two
volatile boolean
volatile boolean running = true;
running = false;This is a single read/write operation.
Good use of volatile.
volatile counter
volatile int count = 0;
count++;This is:
READ → MODIFY → WRITENot atomic.
6. How to make count++ thread-safe?
Use AtomicInteger:
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();Now the increment is atomic:
Thread 1 ── increment ──┐
├──> Atomic operation
Thread 2 ── increment ──┘Or use synchronization:
synchronized void increment() {
count++;
}Easy way to remember
| Feature | volatile | AtomicInteger | synchronized |
|---|---|---|---|
| Latest value visible | ✅ | ✅ | ✅ |
count++ atomic | ❌ | ✅ | ✅ |
| Prevents lost updates | ❌ | ✅ | ✅ |
| Good for simple flag | ✅ | ✅ | ✅ |
One-line memory trick ๐ง
volatile = "Everyone sees my latest value."
atomic = "Nobody can interrupt my operation halfway."
So:
volatile boolean running;✅ Good for a stop/start flag
while:
volatile int count;
count++;❌ Not enough for a shared counter.
No comments:
Post a Comment