Explain Codes LogoExplain Codes Logo

Difference between volatile and synchronized in Java

java
synchronization
thread-safety
concurrency
Nikita BarsukovbyNikita Barsukov·Oct 16, 2024
TLDR

volatile ensures all threads see the latest value of a single variable. It's great for flags and state reporting without compound actions.

Example:

// Back off, this flag is volatile! private volatile boolean isStopped = false; // "DANGER! Contents under pressure."

On the flip side, synchronized offers mutual exclusion, allowing only one thread inside a method or block. Perfect for atomic operations or dealing with multiple variables.

Example:

// No ticket, no laundry! public synchronized void safeAction() { // "Can't touch this." - MC Hammer }

In a nutshell: use volatile for cost-efficient synchronization of single variables and synchronized for complete thread-safety of compound actions.

Synchronization 101

Understanding volatile

A volatile field guarantees that all threads see a coherent value for the variable, avoiding caching issues without any need for locking. It's like a freshly baked pie always ready for serving.

Grasping synchronized

Unlike volatile, synchronized offers atomicity for compound actions by locking access to a resource. Here, the operations inside the synchronized block are like a bicycle - they only work if all the parts are effectively assembled.

Volatile versus synchronized

While volatile allows multi-threaded reading without locking, synchronized uses intrinsic locks ensuring exclusive access, much like a restroom where only one person can enter at a time!

When to use volatile or synchronized

Single variable use-case

For instant updates to a sensor value or status flag by one thread and read by others - volatile is your go-to keyword!

Multiple variable or compound operation use-case

Got a complicated task like updating account balances? Or changing states of multiple variables? synchronized is the bouncer who ensures atomic execution of your code, keeping your data party crasher-free.

Performance chess game

Understanding your requirements is crucial. volatile is your rook, moving straight efficiently in low latency, but restricted when a complex move (compound action) is needed, that's when your queen, synchronized, steps in with stronger consistency.

Going beyond basics

Pre and post-Java 5 scenario

There was a time when volatile was not particularly strong (pre-Java 5). But post-Java 5, volatile hit the gym and now, together with synchronized, you can trust it for robust thread visibility!

The memory fence

Both volatile and synchronized enforce a happens-before consistency, acting as memory barriers. They ensure that your memory actions (reads/writes) don't get reordered like a shuffled playlist.

Advanced gear for synchronization

Explicit locks utilizing concurrency toolkit

java.util.concurrent.locks package upgrades your intrinsic locks by providing ReentrantLock, ReadWriteLock, and others for more refined control. It's like having a Swiss Army Knife instead of just a plain knife.

Atomic variables for single-variable operations

If you're looking to write lock-free thread-safe code, java.util.concurrent.atomic package is your new best friend. It offers atomic operations on single variables like CAS (compare-and-swap).

Real-time scenarios

The volatile fan club: Gaming and live feeds

In gaming or live data feeds, everyone wants to know what's happening right now, volatile gives them just that - a real-time response without complex state management.

The synchronized party: Finance and workflows

Complex operations like financial transactions and multi-step workflows need a gatekeeper - an atomic operations bouncer - enter synchronized!

Masterclass with Lawrence Dol

Lawrence Dol's "read-write-update" model strikes a balance using volatile for read operations, synchronized for write operations, and explicit locks for update operations - graceful as a ballet dancer.