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
running
that 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 |