Both establish happens-before, so both fix visibility and ordering. The difference is atomicity and scope: synchronized provides mutual exclusion over a region of code (any number of fields, compound actions), while volatile only governs a single field and provides no mutual exclusion. Use volatile when a single thread writes and others read, with no read-modify-write.
When volatile suffices
volatile is enough when the write does not depend on the current value and you only need fresh single-field reads. The canonical cases:
- A status flag flipped once:
volatile boolean shutdown;— one writer flips it, many readers poll it. - Safe publication of an already-built value:
volatile Config config;— assign a fully-constructed immutable object, readers see it whole (via the volatile happens-before edge).
class Worker implements Runnable {
private volatile boolean running = true; // visibility is all we need
public void run() {
while (running) { doWork(); } // sees the flip promptly
}
public void stop() { running = false; } // simple assignment, not compound
}
When you need synchronized (or locks/atomics)
The moment you have a compound action — read-modify-write or check-then-act — volatile is insufficient because it doesn't make the sequence atomic.
volatile int count;
void inc() { count++; } // BROKEN: lost updates
synchronized void incSafe() { count++; } // atomic + visible
You also need a lock when an invariant spans multiple fields that must change together (e.g. low <= high); volatile can only make each field individually visible, not keep them mutually consistent.
| Operation | Best | Average | Worst | Note |
|---|---|---|---|---|
| Mutual exclusion | no | volatile | yes (synchronized) | only synchronized blocks other threads |
| Visibility | yes | both | yes | both create happens-before |
| Compound atomicity | no | volatile | yes (synchronized) | volatile can't make i++ atomic |
| Blocking / context switch | none | volatile | possible (synchronized) | volatile never blocks |
| Scope | one field | volatile | code region (synchronized) | lock guards many fields |