Multithreading
volatile Keyword
Understand CPU caches, memory visibility, instruction reordering, and the volatile keyword.
Interview: Commonly tested on the distinction between memory visibility and atomicity, and when volatile is/isn't sufficient.
In a multi-core processor, each core has its own local memory cache. The volatile keyword guarantees that modifications to a variable are immediately visible to all threads, preventing memory visibility issues.
Core Idea
Volatile forces reads/writes of a variable to go directly to main memory, bypassing CPU local caches.
Why It Matters
Without volatile, a thread might check a termination flag cached in its core and run forever, missing the shutdown call.
Interview Lens
Expect questions on why volatile does not make compound operations (like count++) thread-safe.
Visibility vs. Atomicity
It is critical to distinguish between these two concepts:
- Visibility: Ensures changes made by one thread to a variable are visible to other threads.
volatileguarantees visibility. - Atomicity: Ensures a set of actions executes as a single, indivisible step.
volatiledoes NOT provide atomicity. For example,volatileCount++is still not thread-safe. - Instruction Reordering: The compiler and CPU reorder instructions to optimize execution.
volatileestablishes a happens-before relationship, preventing reordering around volatile reads/writes.
Code Walkthrough
The following example demonstrates a thread shutdown coordinator using a volatile flag.
public class VolatileFlagDemo { private static volatile boolean keepRunning = true;public static void main(String[] args) throws InterruptedException { Thread worker = new Thread(() -> { long count = 0; while (keepRunning) { count++; } System.out.println("Worker stopped. Counted: " + count); });
worker.start(); Thread.sleep(1000); // Let worker run for a second
System.out.println("Signaling stop..."); keepRunning = false; // Directly modifies main memory worker.join(); } }
Interview-Relevant Information
Q: When is it safe to use volatile instead of synchronized/locks?
Answer: You can use volatile only when:
1. The write operation does not depend on the variable's current value (e.g. flag checks, status switches).
2. The variable does not participate in invariants with other state variables.
If writes depend on reads (like increments), you must use locks or atomic classes.
Quick Checklist
Does volatile guarantee atomicity? Why can CPU caches hide variable changes? What is instruction reordering? If yes, you understand the volatile keyword.
Use Cases
Shutdown flags and heartbeat loops inside worker threads.
Double-checked locking implementation of thread-safe singletons (requires volatile to prevent partial object construction reordering).
Common Mistakes
Using volatile to protect counters or shared accumulators, leading to race conditions and lost updates.
Thinking volatile variables block execution (they are completely non-blocking).