A volatile variable is a special type of variable in Java that guarantees visibility of changes across multiple threads. When a variable is declared as volatile, every read operation retrieves the latest value directly from main memory, and every write operation is immediately visible to other threads.
Key Points: • volatile ensures that all threads see the most recent value of a variable. • It prevents threads from using stale cached values. • volatile provides visibility but does not guarantee atomicity. • It is commonly used for status flags and control variables shared between threads. • volatile is lighter and faster than synchronization for simple read/write operations.
Why Do We Need volatile?
In a multithreaded environment, each thread may maintain its own local cache of variables.
Without volatile:
Thread 1 updates a variable.
Thread 2 may continue reading an old cached value.
This can lead to inconsistent behavior.
With volatile:
• Changes are written directly to main memory. • Other threads immediately see the updated value.
Example: Suppose one thread starts a background task and another thread needs to stop it.
Without volatile:
The worker thread may never see the updated stop flag.
With volatile:
The worker thread always reads the latest value and stops correctly.
Code Example:
class Worker {
private volatile boolean running =
true;
public void run() {
while (running) {
// Performing work
}
System.out.println(
"Worker Stopped");
}
public void stop() {
running = false;
}
}How volatile Works
Without volatile:
Main Memory | | Thread A Cache Thread B Cache
Thread B may read an outdated value.
With volatile:
Main Memory | | Thread A <----> Thread B
Every read and write interacts with the latest value in main memory.
What volatile Guarantees
1. Visibility
When one thread updates a volatile variable, all other threads immediately see the updated value.
2. Happens-Before Relationship
A write to a volatile variable happens-before every subsequent read of that variable.
This helps maintain memory consistency between threads.
What volatile Does NOT Guarantee
volatile does not make compound operations atomic.
Example:
volatile int counter = 0;
counter++;The increment operation consists of:
1. Read value 2. Increment value 3. Write value
Multiple threads can interfere during these steps.
Result:
Incorrect values may still occur.
For atomic operations, use:
• synchronized • AtomicInteger • Locks
Example of Incorrect Usage
private volatile int counter = 0;
public void increment() {
counter++;
}This is not thread-safe.
Correct Approach:
private AtomicInteger counter =
new AtomicInteger(0);
public void increment() {
counter.incrementAndGet();
}Common Use Cases
• Shutdown flags • Application status indicators • Configuration refresh flags • Thread communication signals • Feature toggles
Example:
private volatile boolean shutdown =
false;One thread updates:
shutdown = true;
Other threads immediately observe the change.
volatile vs synchronized
volatile:
• Ensures visibility • Does not provide atomicity • Faster performance • Suitable for simple flags
synchronized:
• Ensures visibility • Provides atomicity • Uses locking • Suitable for critical sections
Real-World Example
In a web server:
Thread 1:
Updates application status.
serverRunning = false;
Thread 2:
Checks serverRunning continuously.
Using volatile ensures that Thread 2 immediately detects the shutdown request.
Interview Tip: A concise interview answer is:
"A volatile variable ensures that changes made by one thread are immediately visible to all other threads. It guarantees visibility and memory consistency but does not provide atomicity. Therefore, volatile is ideal for shared flags and status variables, while synchronized or Atomic classes should be used for compound operations such as incrementing counters."