Java Interview Questions
Java
Web DevelopmentBackendQuestion 23
What is the 'volatile' keyword in Java?
Answer:
The volatile keyword in Java is used to indicate that a variable's value will be modified by different threads. When a variable is declared as volatile, it ensures that its value is always read from the main memory, and not from the thread's local cache, thereby ensuring visibility of changes across threads.
Key Characteristics of volatile
- Visibility: Ensures that changes to a variable are visible to all threads.
- Atomicity: Does not guarantee atomicity of compound actions. For example, operations like incrementing a
volatilevariable are not atomic. - No Caching: Prevents the caching of the variable in thread-local memory.
When to Use volatile
The volatile keyword is useful when you have a variable that is shared between multiple threads, and you need to ensure that changes made by one thread are visible to other threads. It is typically used for flags, state variables, or any variable that is read and written by multiple threads.
Example of Using volatile
Consider a scenario where a flag is used to control the termination of a thread:
public class VolatileExample {
private volatile boolean running = true;
public void run() {
while (running) {
System.out.println("Thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("Thread stopped.");
}
public void stop() {
running = false;
}
public static void main(String[] args) throws InterruptedException {
VolatileExample example = new VolatileExample();
Thread thread = new Thread(example::run);
thread.start();
Thread.sleep(5000); // Let the thread run for a while
example.stop(); // Stop the thread
}
}
Explanation
-
Declaration:
private volatile boolean running = true;The
runningvariable is declared asvolatile, ensuring that any changes made to it are visible to all threads. -
Read and Write:
- The
runmethod continuously checks the value ofrunning. - The
stopmethod sets the value ofrunningtofalse.
- The
-
Thread Behavior:
- The main thread starts a new thread that runs the
runmethod. - After 5 seconds, the main thread calls the
stopmethod to change therunningvariable tofalse, causing therunmethod to exit the loop and stop the thread.
- The main thread starts a new thread that runs the
Volatile vs. Synchronized
-
Volatile:
- Ensures visibility of changes across threads.
- Does not provide atomicity for compound actions.
- Does not block other threads; lightweight compared to synchronized.
- Suitable for simple flags or state variables.
-
Synchronized:
- Ensures visibility and atomicity.
- Provides exclusive access to a block of code or method.
- Can lead to thread contention and performance overhead due to locking.
- Suitable for complex operations involving multiple steps or shared data structures.
Example of Volatile Limitation
The volatile keyword does not ensure atomicity for compound actions. For instance:
public class VolatileCounter {
private volatile int count = 0;
public void increment() {
count++; // Not atomic
}
public int getCount() {
return count;
}
public static void main(String[] args) {
VolatileCounter counter = new VolatileCounter();
// Create multiple threads that increment the counter
for (int i = 0; i < 1000; i++) {
new Thread(counter::increment).start();
}
// Wait for a while to let threads finish
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Output the count
System.out.println("Count: " + counter.getCount()); // Output might not be 1000
}
}
In this example, the increment operation (count++) is not atomic, and multiple threads may interfere with each other, leading to incorrect results. To ensure atomicity, you need to use synchronization or AtomicInteger.
Conclusion
The volatile keyword in Java is a useful tool for ensuring visibility of shared variables across threads. It is lightweight compared to synchronization but does not provide atomicity for compound operations. Understanding when and how to use volatile is essential for writing correct and efficient multithreaded programs.