In Java, the volatile keyword is used to indicate that a variable’s value may be changed by multiple threads, and that all threads should always see the most up-to-date value of that variable.
It’s a key concept in multithreading and concurrency.
🧠 Definition
A volatile variable is one whose reads and writes go directly to main memory, rather than being cached in a thread’s local memory (CPU cache).
Without volatile:
- Each thread might keep its own cached copy of a variable.
- Changes made by one thread might not be visible to others immediately.
With volatile:
- Every read or write goes to main memory.
- Changes are immediately visible to all threads.
✅ Example Without volatile
class ExampleWithoutVolatile {
private static boolean running = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (running) {
// Busy-wait
}
System.out.println("Thread stopped");
});
t.start();
Thread.sleep(1000);
running = false; // Main thread stops the loop
System.out.println("Main thread set running = false");
}
}
❌ Problem:
- The worker thread might never stop because it keeps reading a cached copy of
runningthat remainstrue.
✅ Fix Using volatile
class ExampleWithVolatile {
private static volatile boolean running = true;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (running) {
// Busy-wait
}
System.out.println("Thread stopped");
});
t.start();
Thread.sleep(1000);
running = false; // Immediately visible to the other thread
System.out.println("Main thread set running = false");
}
}
✅ Output:
Main thread set running = false
Thread stopped
Now the worker thread sees the updated value.
⚙️ Key Properties of volatile
| Property | Description |
|---|---|
| Visibility | All threads see the most recent value of a volatile variable. |
| Atomicity | Only reads and writes to volatile variables are atomic (not compound operations). |
| No locking | Does not block threads — lighter than synchronized. |
| Memory barrier | Prevents reordering of reads/writes across volatile boundaries (important for the Java Memory Model). |
⚠️ Limitations
volatile does not make compound actions atomic.
For example:
volatile int count = 0;
void increment() {
count++; // NOT atomic — it’s read, increment, then write
}
Even though count is volatile, two threads could still interleave:
- Thread A reads 5
- Thread B reads 5
- Both write 6 → ❌ one increment lost
✅ To fix that, use:
synchronized, or- Atomic classes like
AtomicInteger.
🧩 When to Use volatile
Use it when:
- One thread writes to a variable.
- Other threads only read it.
- You don’t need atomic compound updates.
✅ Examples:
- Status flags (e.g.,
isRunning,shutdownRequested) - Configuration changes read by multiple threads
- Double-checked locking pattern (in combination with synchronization)
💡 Quick Summary
| Aspect | volatile |
|---|---|
| Guarantees visibility | ✅ Yes |
| Guarantees atomicity | ❌ No (except for reads/writes) |
| Prevents instruction reordering | ✅ Yes |
| Use case | Shared flags, status indicators |
| Alternative for atomic updates | AtomicInteger, synchronized |
