For working professionals
For fresh graduates
More
6. JDK in Java
7. C++ Vs Java
16. Java If-else
18. Loops in Java
20. For Loop in Java
46. Packages in Java
53. Java Collection
56. Generics In Java
57. Java Interfaces
60. Streams in Java
63. Thread in Java
67. Deadlock in Java
74. Applet in Java
75. Java Swing
76. Java Frameworks
78. JUnit Testing
81. Jar file in Java
82. Java Clean Code
86. Java 8 features
87. String in Java
93. HashMap in Java
98. Enum in Java
101. Hashcode in Java
105. Linked List in Java
109. Array Length in Java
111. Split in java
112. Map In Java
115. HashSet in Java
118. DateFormat in Java
121. Java List Size
122. Java APIs
128. Identifiers in Java
130. Set in Java
132. Try Catch in Java
133. Bubble Sort in Java
135. Queue in Java
142. Jagged Array in Java
144. Java String Format
145. Replace in Java
146. charAt() in Java
147. CompareTo in Java
151. parseInt in Java
153. Abstraction in Java
154. String Input in Java
156. instanceof in Java
157. Math Floor in Java
158. Selection Sort Java
159. int to char in Java
164. Deque in Java
172. Trim in Java
173. RxJava
174. Recursion in Java
175. HashSet Java
177. Square Root in Java
190. Javafx
In Java, when multiple threads access shared data, things can quickly get tricky. One thread might change a variable, but others might not immediately see the updated value. This is where the volatile keyword comes in. It helps ensure that all threads see the most recent value of a variable.
The volatile keyword is a part of Java’s concurrency toolbox. While it doesn’t replace synchronization, it plays a vital role in improving memory visibility and avoiding unexpected behavior in multi-threaded programs.
In this blog, you'll learn what volatile means in Java, how it works behind the scenes, and when to use it—with clear explanations and working code examples.
Want to build stronger Java skills? Online software engineering courses can help you learn faster and better.
The volatile keyword in Java programming is a field modifier used primarily to indicate that a variable's value may be changed by multiple threads simultaneously. When a field is declared volatile, it tells the JVM that reads and writes to this variable should bypass the CPU cache and be performed directly on main memory.
public class VolatileExample {
// Declaration of a volatile variable
private volatile boolean flag = false;
// Methods that use the volatile variable
public void setFlag() {
flag = true; // Write directly to main memory
}
public boolean isFlag() {
return flag; // Read directly from main memory
}
}
To understand the volatile keyword fully, we need to grasp the basics of the Java Memory Model (JMM):
The volatile keyword forces:
Enhance your abilities through these best-in-class certifications.
The volatile keyword is appropriate in specific scenarios:
public class VolatileThreadTermination {
// Without volatile, the thread might never terminate
private volatile boolean running = true;
public void stop() {
running = false; // Signal the thread to stop
}
public void processData() {
new Thread(() -> {
while (running) {
// Process data
System.out.println("Processing data...");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println("Thread terminated");
}).start();
}
public static void main(String[] args) throws InterruptedException {
VolatileThreadTermination processor = new VolatileThreadTermination();
processor.processData();
// Let the thread run for a while
Thread.sleep(500);
// Stop the thread
processor.stop();
System.out.println("Stop signal sent");
}
}
Output:
Processing data...
Processing data...
Processing data...
Processing data...
Processing data...
Stop signal sent
Thread terminated
In this example:
public class VolatileVisibilityDemo {
private volatile boolean volatileFlag = false;
private boolean nonVolatileFlag = false;
// Thread to modify both flags
public void startModifierThread() {
new Thread(() -> {
try {
Thread.sleep(1000);
volatileFlag = true;
nonVolatileFlag = true;
System.out.println("Flags modified by thread");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}).start();
}
// Method to check both flags
public void checkFlags() {
while (!volatileFlag) {
// Wait until volatile flag becomes true
}
System.out.println("Volatile flag detected as true");
// At this point, nonVolatileFlag might still be false in this thread's cache!
if (nonVolatileFlag) {
System.out.println("Non-volatile flag is also visible as true");
} else {
System.out.println("Non-volatile flag not visible yet, still false in this thread's view");
}
}
public static void main(String[] args) {
VolatileVisibilityDemo demo = new VolatileVisibilityDemo();
demo.startModifierThread();
demo.checkFlags();
}
}
Output:
Flags modified by thread
Volatile flag detected as true
Non-volatile flag is also visible as true
Note: The actual output might vary depending on the JVM implementation and hardware. In some cases, the non-volatile flag might not be immediately visible, demonstrating the memory visibility issue.
public class VolatileSingleton {
// The volatile keyword is critical here
private static volatile VolatileSingleton instance;
// Private constructor prevents instantiation
private VolatileSingleton() {
System.out.println("Singleton instance created");
}
// Double-checked locking pattern
public static VolatileSingleton getInstance() {
if (instance == null) {
synchronized (VolatileSingleton.class) {
if (instance == null) {
instance = new VolatileSingleton();
}
}
}
return instance;
}
public void showMessage() {
System.out.println("Singleton method called");
}
public static void main(String[] args) {
// Create threads that attempt to get the singleton instance
for (int i = 0; i < 5; i++) {
new Thread(() -> {
VolatileSingleton singleton = VolatileSingleton.getInstance();
singleton.showMessage();
}).start();
}
}
}
Output:
Singleton instance created
Singleton method called
Singleton method called
Singleton method called
Singleton method called
Singleton method called
In this example:
While powerful, the volatile keyword has several important limitations:
Let's compare volatile with synchronized to understand their different use cases:
Feature | volatile | synchronized |
Purpose | Memory visibility | Mutual exclusion |
Scope | Applies to variables | Applies to code blocks or methods |
Atomic operations | Only single read/write operations | All operations within the block |
Performance impact | Lower overhead | Higher overhead |
Thread blocking | No | Yes |
Lock acquisition | No | Yes |
Use case | Simple flags, status indicators | Complex operations requiring atomicity |
Memory consistency | Only for the volatile variable | For all variables within the block |
The Java Memory Model defines the "happens-before" relationship, which is crucial for understanding volatile:
This relationship creates a memory barrier that ensures orderly visibility of not just the volatile variable but also other variables modified before the volatile write.
Even experienced developers can misuse volatile. Here are common pitfalls to avoid:
When volatile isn't sufficient, consider these alternatives:
Using volatile has performance implications:
Best Practices for Using Volatile Keyword in Java
To use volatile effectively:
The volatile keyword in Java is a powerful tool for ensuring memory visibility in multi-threaded applications. By understanding what the volatile keyword in Java does, how it works with the Java Memory Model, and when to use it, you can write more efficient and reliable concurrent code.
Remember that volatile is not a silver bullet for all concurrency issues—it's best suited for simple flags and status indicators where visibility, not atomicity, is the primary concern. For more complex scenarios, combine volatile with other concurrency tools or consider higher-level abstractions from the java.util.concurrent package.
By applying the knowledge, examples, and best practices outlined in this guide, you'll be well-equipped to use the volatile keyword effectively in your Java applications.
The primary purpose of the volatile keyword is to ensure memory visibility across threads. When a variable is declared volatile, any thread reading the variable will see the most recently written value by any thread, as it forces operations to be performed on main memory rather than CPU caches.
No, volatile only guarantees visibility of the latest value. It makes single reads and writes atomic but doesn't make compound operations (like increment) atomic. For atomic operations on a single variable, consider using classes from the java.util.concurrent.atomic package instead.
Yes, you can declare an array as volatile, but this only makes the reference to the array volatile, not the array elements. Operations on the array elements are not guaranteed to be visible across threads unless you take additional synchronization measures.
Volatile variables bypass CPU caches and operate directly on main memory, which can be slower than cache access. However, volatile is still much faster than using synchronized blocks. Use volatile when visibility is the only concern and synchronized when atomicity is required.
Use volatile when you only need visibility guarantees and not atomicity or mutual exclusion. Volatile is appropriate for simple flags, status indicators, and the double-checked locking pattern. Use synchronized for more complex scenarios requiring atomic operations or maintaining invariants across multiple variables.
Yes, final variables also provide visibility guarantees in Java. When a final field is initialized in a constructor, it's guaranteed that any thread that sees the object will also see the correct value of the final field. However, final can't be used when the variable needs to change after initialization.
No, volatile has no effect in single-threaded applications since there's no concern about memory visibility across multiple threads. Using volatile in such contexts only adds unnecessary overhead.
The Java Memory Model (JMM) specifies that writes to a volatile variable establish a happens-before relationship with subsequent reads of that variable. This means that not only is the volatile variable itself visible, but all variables modified before writing to the volatile variable are also visible to other threads that read the volatile variable.
Yes, volatile prevents the reordering of instructions around volatile variable access. The JVM cannot reorder instructions in a way that would place a volatile read/write before instructions that precede it in the code, or after instructions that follow it in the code.
No, volatile only works within a single JVM. For distributed systems or applications running across multiple JVMs, you would need to use other mechanisms like distributed locks, databases, or message queues to achieve similar visibility guarantees.
It's not recommended. When you use volatile with wrapper classes (like Integer, Long, etc.), the reference to the object is volatile, but the internal state is not. Since wrapper classes are immutable, operations like incrementing actually create new objects. Use AtomicInteger or similar classes instead for mutable, thread-safe numeric operations.
Take the Free Quiz on Java
Answer quick questions and assess your Java knowledge
Author
Disclaimer
1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.
2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.