Difference between volatile and synchronized in Java
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
In Java, writing multithreaded programs often involves managing shared resources and ensuring that concurrent access to these resources does not lead to inconsistent results. Two concepts that play a critical role in this scenario are volatile and synchronized. While both deal with the visibility and access of shared variables, they serve different purposes and are used under different circumstances. In this article, we explore the differences between volatile and synchronized in Java with technical explanations and examples.
Technical Explanation
volatile Keyword
The volatile keyword in Java is used to mark a variable as being stored in the main memory. More importantly, it ensures that any read of the volatile variable always reflects the most recent write by any thread. This addresses the visibility of changes made by one thread to be immediately available to other threads.
Key Points:
- Visibility Guarantee: Changes to a
volatilevariable are always visible to other threads. - No Atomicity: Operations on
volatilevariables are not atomic. This means that compound operations (like incrementing) onvolatilevariables are not thread-safe. - No Locks Needed: Access to
volatilevariables does not require obtaining a lock, resulting in less overhead. - Use Cases: Suitable for flags, completion signals, or caching scenarios where simple state checks are needed.
Example:
In this example, any changes made to flag in one thread will be immediately visible to other threads accessing it.
synchronized Method/Block
The synchronized keyword is used to control access to a block of code or method. It ensures that only one thread can execute the synchronized code at a time, thus providing both atomicity and visibility.
Key Points:
- Atomicity and Visibility:
synchronizedprovides both atomicity and visibility guarantees. - Locks: A thread must acquire the associated lock to enter a
synchronizedmethod/block, which ensures mutual exclusion. - Performance Cost: The locking mechanism introduces some overheads, potentially affecting performance.
- Use Cases: Ideal for critical sections where complex transactions occur, like updating a shared resource.
Example:
In this example, incrementCounter is atomic, meaning one thread can increment the counter without interference from other threads.
Table Summary: volatile vs synchronized
| Feature | volatile | synchronized |
| Visibility Control | Ensures visibility of changes | Ensures visibility and atomicity |
| Locking | Does not use locks | Manages locks for mutual exclusion |
| Overhead Cost | Low due to no lock overhead | Higher due to lock acquisition |
| Use Case | Simple flags or states | Complex transactions |
Additional Considerations
When to Use volatile
volatile is suitable in scenarios where a variable is used for checking simple state conditions or flags, and when setting and reading a variable is the only operation needed. It's important to note that if the operation requires more than a simple read or write, volatile may not be sufficient, as it does not guarantee atomicity.
When to Use synchronized
Use synchronized when fine-grained control is needed over accessing a particular piece of code or shared resource. It is effective in situations where more complicated states exist and multiple operations need to appear as a single atomic action.
Combining volatile and synchronized
Though often used separately, there are use cases where both volatile and synchronized might be used together. For instance, using volatile for read-heavy shared variables along with synchronization to ensure atomic updates can leverage the strengths of both mechanisms.
Conclusion
Understanding the difference between volatile and synchronized helps in making informed decisions when designing multithreaded applications. While volatile is lightweight and easy to implement, synchronized offers comprehensive control over critical sections. Choosing the right mechanism depends largely on the specific needs of the application, making it essential to comprehend both their capabilities and limitations.

