How to Properly Use Synchronized and Volatile in Your Java Application

Don’t misuse synchronized and volatile in your application.

Vikram Gupta
Feb 18 · 6 min read
Cache Coherence

I have seen many developers a bit confused when it comes to multi-threading. This is primarily because a lot of things happen in the background and many concepts are related to it. You should know Race Condition, Critical section, and Context Switching between threads. I have already covered these concepts and their examples in detail.

Process and Thread Context Switching, Do You Know the Difference?

Synchronization in Java: All You Need to Know

In this article, I’ll be covering two important keywords synchronized and volatile, and their proper usage. This is one of the most asked interview questions from the multi-threading area.

Before diving into the actual topic let me explain what is Cache Coherence. This is required to understand the concept of volatility and synchronization.

In a shared-memory multiprocessor system with a separate cache memory for each processor, it is possible to have many copies of shared data: one copy in the main memory and one in the local cache of each processor that requested it. When one of the copies of data is changed, the other copies must reflect that change. Cache coherence is the discipline that ensures that the changes in the values of shared data/variables are propagated throughout the system in a timely fashion.

Visualizing Cache InCoherence:

Cache InCoherence

P1 and P2 are two processes using two local caches. In this example, we can see the data is not consistent because of two write operations by two different processes having two different values in their local caches.

Visualizing Cache Coherence:

Cache Coherence

The same P1 and P2 are using two local caches. But, we can see once the data is updated by one process it is written into the main memory and other local caches also get the updated value. Hence the data is consistent because of forceful write operations by these different processes having two different values in their local caches.

When we use a synchronized keyword with a block/method to avoid a race condition, java internally uses an intrinsic or monitor lock which is bound to an object. Hence at any given point, only one thread can access the synchronized block/method.

The synchronized keyword can be used with :

  1. Instance method
  2. Static method
  3. Code block inside an instance method
  4. Code block inside a static method

I have already written a complete article on Thread Synchronization. Before reading this article I would suggest you should go through this article for a better and complete understanding of synchronization and multi-threading.

The volatile keyword is used in multithreaded applications. It is used as a field modifier (alongside private, public, etc) to indicate that the field may be accessed by multiple Java threads. For example, we can declare that a boolean flag is accessed by multiple threads:

private volatile boolean stopFlag = false;

Using volatile is one potential way of ensuring that your Java program is thread-safe and will behave as expected when multiple threads access the value of the variable. We may use the synchronized keyword for maintaining thread safety. However, the volatile keyword is essentially lock-free and hence the most lightweight means of providing thread safety.

Declaring a Volatile Variable Simply Means:

  • The value of this variable will never be cached in the threads' caches locally. Every read and writes operation performed by each thread will go straight to the main memory.
  • Access to the volatile variable acts as though it is enclosed in a synchronized block, I mean synchronized on itself.
  1. A primitive variable may be declared as volatile because we cannot synchronize on a primitive variable with the synchronized keyword as the primitive variable does not have an intrinsic lock. Basically, an intrinsic lock (aka monitor lock) is an implicit internal entity associated with each instance of an object. The intrinsic lock enforces exclusive access to an object’s state. As long as a thread owns an intrinsic lock, no other thread can acquire the same lock.
  2. Access to a volatile variable never has the potential to block the threads. It means we’re only ever doing a simple read or write, so unlike a synchronized block we will never hold on to any lock.
  3. Because accessing a volatile variable never holds a lock, it is not suitable for cases where we want to read-update-write as an atomic operation (unless we’re prepared to “miss an update”).
  4. A volatile variable that is an object reference may be null (because you’re effectively synchronizing on the reference, not the actual object).
  1. When a thread writes the value of the volatile field, the value it writes does not depend on the previous value just read.
  2. When you have a simple flag or other primitive items of data that are accessed by multiple threads.
  3. When you have a more complex immutable object that is initialized by one thread then accessed by others: here you want to update the reference to the immutable data structure and allow other threads to reference it.

Let’s understand it by taking an example:

class TestVolatile{
int myInt = 0;
char myChar = 'c';
}

If we declare a reference of this class as follows:

private volatile TestVolatile testVolatile ;

Only the object reference will be considered to be volatile by the JVM and not the object data itself (myInt and myChar)which will reside on the heap.

If we required the member variables of the object on the heap to be volatile we can of course apply the keyword to these primitives as well.

class TestVolatile{
volatile int myInt = 0;
volatile char myChar = 'c';
}

Note that the question of whether this makes the variable testVolatilethread-safe depends on how you are using the variable.

As the volatile keyword does help with a read or write to be directly into main memory, however, be noted that this is not the same as it always being thread-safe.

if(testVolatile != null) {
testVolatile.doSomething();
}

It is still possible that a thread that executes the null check, is interrupted before it executes, testVolatile.doSomething()and another thread sets testVolatile = null. Hence there is a chance of getting NullPointerException . Some other mechanism is required here such as a synchronized block to get rid of this Exception.

That’s all for this article. I hope you have got a clear idea about synchronized and volatile.

If you liked this article, consider following me. I mostly write on java programming, data structures, algorithms, SQL, GIT, Linux, best practices, etc.

Thank you for reading it.

KEEP LEARNING KEEP GROWING!!!

The Startup

Get smarter at building your thing. Join The Startup’s +724K followers.

Vikram Gupta

Written by

| Software Developer | Programming enthusiast | Loves DS and Algo | Passionate about Future | Writes Mostly tech stuff |

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +724K followers.

Vikram Gupta

Written by

| Software Developer | Programming enthusiast | Loves DS and Algo | Passionate about Future | Writes Mostly tech stuff |

The Startup

Get smarter at building your thing. Follow to join The Startup’s +8 million monthly readers & +724K followers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store