Question
While working with Java code, I encountered the volatile keyword and am not familiar with it. What is volatile used for in Java? In which situations is it appropriate to use it correctly, and when should another concurrency tool be used instead?
Short Answer
By the end of this page, you will understand how volatile makes updates to a field visible across threads, why it is useful for simple state flags, and why it does not make operations such as count++ thread-safe.
Concept
volatile is a Java field modifier used in concurrent programs: programs where multiple threads run at the same time.
When one thread changes an ordinary field, another thread is not guaranteed to notice that change immediately. Threads may temporarily read cached or reordered values for performance. Declaring a field volatile creates a visibility guarantee:
- A write to a
volatilefield by one thread becomes visible to other threads that subsequently read that field. - Reads and writes of the individual
volatilefield are atomic. - A write to a
volatilefield also makes earlier writes by that thread visible to a thread that reads the updated volatile value.
This makes volatile a good fit for simple shared state, especially a flag that one thread sets and another thread checks.
However, volatile does not turn a sequence of operations into one indivisible operation. For example, count++ means read, add one, then write. Two threads can interleave those steps and lose an update, even when count is volatile.
Use volatile for visibility. Use synchronized, locks, or atomic classes when you need to coordinate or atomically update shared state.
Mental Model
Imagine each thread has a desk with a copy of a shared notice board.
Without volatile, a worker may keep looking at an older copy on their desk. A manager can change running to false on the main board, but the worker is not guaranteed to see the new value promptly.
A volatile field is like a notice that must be checked against the shared board. When the manager updates it, workers who check it can see the latest update.
It does not make a multi-step task safe. If two workers both read “10”, each calculate “11”, and each write “11”, one increment is still lost. For that, you need a turn-taking mechanism such as synchronized or AtomicInteger.
Syntax and Examples
Declare volatile on an instance or static field:
private volatile boolean running = true;
A common example is stopping a worker thread:
public class Worker implements Runnable {
private volatile boolean running = true;
public void stop() {
running = false;
}
@Override
public void run() {
while (running) {
System.out.println("Working...");
}
System.out.println("Worker stopped.");
}
}
One thread runs run(). Another thread calls stop(). Because running is volatile, the loop can observe the value and finish.
Step by Step Execution
Consider this example:
public class StopDemo {
private volatile boolean running = true;
public void work() {
while (running) {
// Perform a small unit of work.
}
System.out.println("Stopped");
}
public void requestStop() {
running = false;
}
}
Execution trace:
- A worker thread calls
work(). Initially,runningistrue. - The worker repeatedly evaluates
while (running)and continues working. - Another thread calls
requestStop(). - That thread writes
falseto the volatilerunningfield. - A later loop condition check by the worker reads the updated value.
- The condition is now false, so the loop exits.
Real World Use Cases
volatile is most useful when a field represents one independently readable and writable piece of state.
- Shutdown flags: Stop a background polling, monitoring, or maintenance thread.
- Cancellation requests: Allow a long-running computation to periodically check whether it should end. Use interruption too when the thread can block in methods such as
sleep()orwait(). - Latest configuration snapshot: Publish an immutable configuration object that readers may replace and read safely.
- Status fields: Expose a current state such as
STARTING,READY, orCLOSED, when no multi-field atomic transition is required. - One-time publication patterns: Publish fully initialized data by writing a volatile reference after initialization.
For queues, counters, work scheduling, and complex shared mutable data, prefer established concurrency tools such as BlockingQueue, ConcurrentHashMap, AtomicInteger, executors, and locks.
Real Codebase Usage
In production code, volatile is often used sparingly and paired with a clear ownership rule.
Guard a loop with a shutdown flag
private volatile boolean closed;
public void runLoop() {
while (!closed) {
processNextItem();
}
}
public void close() {
closed = true;
}
This is appropriate only if processNextItem() returns regularly. If it blocks, close() may also need to interrupt the worker thread or close the blocking resource.
Publish an immutable snapshot
private volatile AppConfig config = AppConfig.defaults();
public void reload(AppConfig newConfig) {
config = newConfig;
}
public int timeoutMillis() {
return config.timeoutMillis();
}
Common Mistakes
Assuming volatile makes count++ safe
This is broken when multiple threads increment the counter:
private volatile int count = 0;
public void increment() {
count++;
}
count++ is a read-modify-write sequence, not one atomic action. Use AtomicInteger instead:
private final AtomicInteger count = new AtomicInteger();
public void increment() {
count.incrementAndGet();
}
Using volatile for related fields that must change together
private volatile int x;
y;
Comparisons
| Tool | Main guarantee | Good use case | Not sufficient for |
|---|---|---|---|
volatile | Visibility of individual field reads/writes and ordering around that field | Stop flags, immutable snapshot references | Atomic multi-step updates |
synchronized | Mutual exclusion, visibility, and ordering | Protecting several fields or a critical section | Non-blocking high-contention counters |
AtomicInteger / AtomicReference | Atomic operations on one value | Counters, compare-and-set state changes | Coordinating complex multi-field invariants |
Lock | Explicit mutual exclusion with advanced lock features | Timed locking, multiple conditions, structured locking |
Cheat Sheet
// Declaration
private volatile boolean running = true;
private volatile Config config;
volatileapplies to fields, not local variables or method parameters.- It guarantees visibility of writes to later readers of that field.
- Reads and writes of the volatile field itself are atomic.
- It does not make
++,+=, check-then-act logic, or multiple fields atomic. - Write data first, then write a volatile
readyflag to publish the data. - Use it for flags, state references, and immutable snapshots.
- Use
AtomicInteger,AtomicReference,synchronized, or locks for atomic updates and invariants. volatile longandvolatile doublereads/writes are atomic in modern Java; compound operations are still not atomic.- For a blocked thread, changing a volatile flag alone may not wake it; consider interruption or closing the underlying resource.
FAQ
What does volatile mean in Java?
It marks a field as shared state whose writes must be visible to other threads that read the field. It also establishes important ordering guarantees around that read and write.
When should I use volatile in Java?
Use it for simple state such as a stop flag or a reference to a fully initialized immutable configuration object. Use stronger coordination when an update involves multiple steps or fields.
Does volatile make Java code thread-safe?
Not by itself. It solves visibility for one field, but it does not provide mutual exclusion or make compound operations atomic.
Is volatile needed for every shared variable?
No. A variable can also be safely accessed through synchronized, locks, atomic classes, concurrent collections, thread confinement, or immutable objects passed safely between threads.
Why is volatile int count; count++ unsafe?
Incrementing requires separate read, calculation, and write steps. Two threads can read the same old value and overwrite each other's result. Use AtomicInteger.incrementAndGet() or synchronization.
Can volatile replace synchronized?
Only for limited cases involving independent state visibility. It cannot replace synchronized when a critical section must protect several operations or preserve a relationship between fields.
Mini Project
Description
Build a small background worker that prints work cycles until another thread requests shutdown. The project demonstrates the appropriate use of a volatile boolean: communicating a simple state change from one thread to another.
Goal
Create and stop a worker thread using a volatile shutdown flag.
Requirements
Use a volatile boolean field initialized to true. Create a worker loop that continues while the flag is true. Provide a method that changes the flag to false. Start the worker from main and request shutdown after a short delay. Wait for the worker thread to finish with join().
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.