volatile Keyword in Java
The volatile
keyword in Java is used to indicate that a variable's value will be modified by different threads. It ensures that changes to a variable are always visible to other threads, preventing thread caching issues.
Usage
The volatile
keyword is primarily used in multi-threaded programming to ensure that a variable's updates are propagated predictably across threads.
Syntax
volatile dataType variableName;
dataType
: The type of the variable (e.g.,int
,boolean
, etc.).variableName
: The name of the variable.
Examples
Example 1: Basic Usage
public class VolatileExample extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
// Thread is running
}
System.out.println("Thread stopped.");
}
public void stopRunning() {
running = false;
}
public static void main(String[] args) throws InterruptedException {
VolatileExample thread = new VolatileExample();
thread.start();
Thread.sleep(1000);
thread.stopRunning();
thread.join();
}
}
In this example, the running
variable is marked as volatile
. The run
method checks the running
variable in a loop. The stopRunning
method sets running
to false
, which stops the loop. The volatile
keyword ensures that changes to running
are immediately visible to the run
method.
Example 2: Volatile with Multiple Threads
public class VolatileCounter {
private volatile int counter = 0;
public void increment() {
counter++;
}
public int getCounter() {
return counter;
}
public static void main(String[] args) throws InterruptedException {
VolatileCounter vc = new VolatileCounter();
Runnable task = () -> {
for (int i = 0; i < 1000; i++) {
vc.increment();
}
};
Thread t1 = new Thread(task);
Thread t2 = new Thread(task);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Counter value: " + vc.getCounter());
}
}
In this example, the counter
variable is marked as volatile
. Two threads increment the counter
variable concurrently. The volatile
keyword ensures that each thread sees the most recent value of counter
.
Tips and Best Practices
- Visibility Guarantee: Use
volatile
to ensure visibility of changes to variables across threads. It guarantees that a read of a volatile variable always returns the most recent write by any thread. - Atomicity:
volatile
does not guarantee atomicity. For compound actions (e.g., increment operations), consider using other synchronization mechanisms likesynchronized
blocks orAtomicInteger
.private AtomicInteger counter = new AtomicInteger(0); counter.incrementAndGet();
- Use Cases: Appropriate for flags, state variables, and other variables where the latest value is critical but compound operations are not required.
- Avoid Overuse: Overusing
volatile
can lead to performance issues. Use it only when necessary to ensure visibility. - Combine with Other Synchronization: In complex scenarios, combine
volatile
with other synchronization mechanisms to ensure both visibility and atomicity.private volatile boolean flag = false; synchronized (this) { flag = true; }
- Memory Consistency: The
volatile
keyword helps prevent memory consistency errors by establishing a happens-before relationship, ensuring that changes to a volatile variable are visible to other threads.