volatile
Keyword in Java
In Java, the volatile
keyword is used with variables to indicate that the value of a variable will be modified by different threads. It's a part of Java's memory management model and is crucial for safe access to shared variables in a concurrent application.
Why Do We Need volatile
?
Java threads may cache variables locally to improve performance. However, this can lead to situations where one thread doesn't see the most recent value of a variable modified by another thread.
By declaring a variable volatile
, we tell the JVM:
- Do not cache the value locally.
- Always read it from and write it to the main memory.
How volatile
Works
Let’s understand this with a simple example. Consider a boolean flag that controls whether a thread should continue running or not.
public class VolatileDemo extends Thread {
private volatile boolean running = true;
public void run() {
System.out.println("Thread started...");
while (running) {
// do work
}
System.out.println("Thread stopped.");
}
public void stopThread() {
running = false;
}
public static void main(String[] args) throws InterruptedException {
VolatileDemo thread = new VolatileDemo();
thread.start();
Thread.sleep(1000);
thread.stopThread(); // this will be seen by the other thread due to volatile
}
}
Thread started...
Thread stopped.
Without volatile
: What Goes Wrong?
If the running
variable is not marked volatile
, the thread might not stop as expected because it could be using a cached version of the variable that never sees the update.
Key Characteristics of volatile
- Visibility: Ensures the updated value is visible to all threads.
- No atomicity: It doesn’t make compound actions (like
count++
) atomic. - No locking: Unlike
synchronized
, it doesn’t use locks, hence it's lightweight and faster.
Common Use Cases for volatile
- Flags for stopping threads.
- Status or state monitoring variables.
- Double-checked locking (used with care).
Example: Visibility Without Synchronization
This demonstrates the difference volatile
makes.
public class WithoutVolatile {
private static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (!flag) {
// busy wait
}
System.out.println("Flag detected as true!");
}).start();
Thread.sleep(1000);
flag = true; // may not be visible to other thread
}
}
(no output - thread is stuck in infinite loop)
Now change flag
to volatile
and you’ll see:
Flag detected as true!
Difference Between volatile
and synchronized
Aspect | volatile |
synchronized |
---|---|---|
Guarantees Visibility | Yes | Yes |
Guarantees Atomicity | No | Yes |
Performance | Faster | Slower (due to locking) |
Use Case | Simple flags or state sharing | Complex critical sections |
Can You Use volatile
for Counters?
No. If you try to use volatile
for increment operations like count++
, it won't be thread-safe because ++
is not an atomic operation. Use AtomicInteger
or synchronization instead.
private volatile int count = 0;
public void increment() {
count++; // not thread-safe!
}