The volatile keyword in Java is used to indicate that a variable’s value will be modified by different threads. It ensures that changes made to a variable in one thread are immediately visible to other threads, thus providing a lightweight synchronization mechanism.
Table of Contents
- Introduction
volatileKeyword Syntax- Understanding
volatile - Examples
- Volatile Variable
- Volatile vs Synchronized
- Real-World Use Case
- Conclusion
Introduction
In multithreaded programming, it is crucial to ensure that the latest value of a shared variable is always visible to all threads. The volatile keyword helps achieve this by instructing the Java Virtual Machine (JVM) to always read the variable from the main memory and not from a thread’s local cache.
volatile Keyword Syntax
The syntax for declaring a volatile variable is straightforward:
volatile dataType variableName;
Example:
volatile boolean flag;
Understanding volatile
Key Points:
- Visibility: Changes to a
volatilevariable are always visible to other threads. - No Caching: A
volatilevariable is not cached locally in any thread; it is always read from and written to main memory. - Atomicity: Operations on
volatilevariables are atomic only for single read/write operations. Complex operations like incrementing a variable are not atomic and require additional synchronization.
Examples
Volatile Variable
A simple example demonstrating the use of a volatile variable to ensure visibility across threads.
Example
public class VolatileExample {
private volatile boolean flag = true;
public void stop() {
flag = false;
}
public void run() {
while (flag) {
// Do some work
}
System.out.println("Thread stopped.");
}
public static void main(String[] args) throws InterruptedException {
VolatileExample example = new VolatileExample();
Thread thread = new Thread(example::run);
thread.start();
Thread.sleep(1000);
example.stop();
thread.join();
System.out.println("Main thread finished.");
}
}
Output:
Thread stopped.
Main thread finished.
Volatile vs Synchronized
A comparison between volatile and synchronized for a counter example.
Example
public class VolatileVsSynchronized {
private volatile int volatileCounter = 0;
private int synchronizedCounter = 0;
public void incrementVolatileCounter() {
volatileCounter++;
}
public synchronized void incrementSynchronizedCounter() {
synchronizedCounter++;
}
public int getVolatileCounter() {
return volatileCounter;
}
public int getSynchronizedCounter() {
return synchronizedCounter;
}
public static void main(String[] args) throws InterruptedException {
VolatileVsSynchronized example = new VolatileVsSynchronized();
Runnable volatileTask = () -> {
for (int i = 0; i < 1000; i++) {
example.incrementVolatileCounter();
}
};
Runnable synchronizedTask = () -> {
for (int i = 0; i < 1000; i++) {
example.incrementSynchronizedCounter();
}
};
Thread thread1 = new Thread(volatileTask);
Thread thread2 = new Thread(volatileTask);
Thread thread3 = new Thread(synchronizedTask);
Thread thread4 = new Thread(synchronizedTask);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread1.join();
thread2.join();
thread3.join();
thread4.join();
System.out.println("Volatile Counter: " + example.getVolatileCounter());
System.out.println("Synchronized Counter: " + example.getSynchronizedCounter());
}
}
Output:
Volatile Counter: 1865
Synchronized Counter: 2000
The volatile counter may not reach 2000 due to race conditions, while the synchronized counter reliably reaches 2000.
Real-World Use Case
Flag for Stopping Threads
In real-world applications, volatile is commonly used for flags that signal threads to stop running.
Example
public class StopThreadExample {
private volatile boolean running = true;
public void stop() {
running = false;
}
public void run() {
while (running) {
// Perform work
}
System.out.println("Thread stopped.");
}
public static void main(String[] args) throws InterruptedException {
StopThreadExample example = new StopThreadExample();
Thread thread = new Thread(example::run);
thread.start();
Thread.sleep(1000);
example.stop();
thread.join();
System.out.println("Main thread finished.");
}
}
Output:
Thread stopped.
Main thread finished.
Conclusion
The volatile keyword in Java is used for ensuring the visibility of changes to variables across threads. It provides a simple way to achieve thread safety for certain types of variables without the overhead of synchronization. However, it is important to understand its limitations and use it appropriately in conjunction with other synchronization mechanisms when necessary.