Java is always being rich with a number of features and volatile keyword in Java is used to provide a crucial support in Multithreading based developments.
However, most of the developers only know that volatile is a keyword, but they don’t have a clear cut idea about What is the use of volatile keyword in Java and where to use volatile?
It’s one of the major reasons, why Multithreading is always a Remarkable topic in Core Java Interviews and in this tutorial, we will take a deep dive into the usage of volatile keyword in Java.
Technically speaking, volatile in Java plays an important role in the Multithreading environment. Let’s start learning- What is volatile keyword, where we can use it, and more. But, before anything else-
Learning Points:
- volatile keyword in Java
- How to use volatile?
- What does volatile do?
- Use cases of volatile in Java
- Side notes on happens-before relationship
- Important points on volatile-Java
Conclusion
What is volatile keyword in Java?
At its core, the volatile provides yet another way of making classes Thread safe (similar to synchronized keyword and atomic wrapper classes). Thread-safety is an essential point when developing a multi-threading application.
When multiple threads invoke methods that manipulate shared variables, Thread safety guarantees the internal state of the class, as well as- returned values from methods, are correct.
By the way, If we look into Java Collections API, there are multiple collection classes that provide built-in Thread safety features. These classes somewhere make use of volatile and synchronized keywords. To name a few-
- Stack class,
- Vector class,
- Hashtable class,
- Properties class, others as well.
There are different pros and cons of using volatile in Java, so Let’s move on to it-
How to use volatile in Java?
The volatile keyword in Java, is used with fields and variables of a Java class. You cannot use volatile keyword with Java classes and methods. When we use volatile with field declarations, the Java Memory Model ensures that all threads see a consistent value for that field or variable.
Volatile keyword in Java takes care of that, the volatile variable must always be read directly from the main memory (RAM) and the “happens-before” relationship in Java Memory model ensures- all the threads must have the actual value from the memory (that we’ll see later in this post).
Example of volatile:
class VolatileUsageExample { static volatile int bookName = "Volatile in Java- A guide by ShubhamKLogic.com"; static void printBookName() { System.out.println( bookName ); } }
So, what does volatile do?
- In simplest words, volatile ensures that all shared variables are consistently and reliably updated (as Java supports MultiThreading and allows threads to access shared variables).
- If a field is declared with volatile keyword, in that case, the Java Memory Model takes care of that all the threads see a consistent value for the particular variable.
- One plus point with volatile is that, it does NOT lock that resource for different purposes and any other thread can manipulate that shared resource at any time.
volatile and synchronized both the keywords work for similar purposes but there are some major differences between their functionalities and permissions. Let’s catch them to understand volatile in Java better-
When is volatile needed (in place of synchronized)?
-
Without volatile:
class BookCounter { static int a = 0, b = 0; // Shared variables... static void first() { a++; b++; } // Method-1 static void second() { // Method-2 System.out.print("a=" + a + " b=" + b); } }
-
Using synchronized keyword
class BookCounter { static int a = 0, b = 0; static synchronized void first() { a++; b++; } // synchronized updation of shared variables... static synchronized void second() { // synchronized the method... System.out.println("a=" + a + " b=" + b); } }
Putting the synchronized keyword in the declaration, prevents method first() and method second() from being executed concurrently, and also ensures that the shared values of a and b are both updated before method first() returns. Therefore method second() NEVER observes any value for b greater than that for a; indeed, it always observes the same value for a and b.
However, Synchronized obtains and releases the lock on resources marked with synchronized keyword, which definitely affects the performance so badly when the number of threads will increase and that’s one of the best cases- when to use volatile in Java.
-
Using volatile keyword
class BookCounter { static volatile int a = 0, b = 0; // Use of volatile... static void first() { a++; b++; } static void second() { System.out.println("a=" + a + " b=" + b); } }
Another approach would be to declare a and b to be volatile. Have a look at the example above. In this way, the methods first() and second() would not only be executed concurrently, but also guarantees that accesses to the shared values for a and b occur exactly as many times, and most importantly- In the same order, as they appear to occur during the execution of the program by each thread.
volatile will take care of, the shared value for b must NEVER be greater than that for a. I repeat- NEVER because each update to a must be reflected in the shared value for a before the updation of b, and the happens-before relationship of Java Memory Model will take care of it.
Side notes on “happens-before” relationship
Let’s understand- How does Java documentation explain a happens-before relationship:
“Two actions can be ordered by a happens-before relationship. If one action happens-before another, then the first is visible to and ordered before the second”.
This simply means, if there is a happens-before relationship between a write and read operation, the results of a write by one thread are guaranteed to be visible to a read by other threads.
In this way, we will gracefully reduce the memory in-consistency. If we are able to have the happens-before relationship between our actions. Apart from the volatility and synchronization, Java defines several sets of rules for a happens-before relationship. If you want to learn more about the rules, find them in detail from the Oracle Docs.
Important points of volatile in Java
1. The volatile keyword in Java can only be used with a field or variable of the class and using a volatile keyword with methods and classes is a compile-time error.
2. volatile keyword in Java takes care of value of the volatile variable that it must always be read from main memory and not from Thread’s local cache.
3. When we use volatile in Java programs, it perfectly reduces the risk of memory consistency errors because read and write to a volatile variable becomes subsequent because of some Java Memory Model relationship known as happens-before relationship.
4. After a major update in Java 4, the new Java 5 came with a different set of rules. From Java 5, every updation of a volatile variable will always be visible to other threads. This simply means, when a thread reads a volatile variable in Java, it sees not only the latest change to the volatile variable but also the side effects of the code that led up the change.
5. If you’ll access to a volatile variable in Java that will never block any resource, since we are only doing a simple read or write. It gracefully improves the performance unlike a synchronized block to hold on to a lock or wait for a lock.
However, it is important to keep note that the volatile keyword should not treat as a replacement for synchronized blocks/methods. It will be useful only when achieving visibility for shared resources as variables using a happens-before relationship. We will still have to use the synchronization in a multithreading environment when we need to achieve mutual exclusiveness between threads.
Conclusion
That’s all about volatile keyword in Java. We have learned a whole lot of different concepts about volatile in Java.
In short, The visibility of writing operations on shared variables can cause problems during delays that occur when writing to the main memory (or say RAM) due to caching in each core. This can result in another thread reading a stale (or say old) value (not the last updated value) of the variable and that’s where volatile comes into the picture.
Multi-threading is playing a tremendous role nowadays in developing fast and feature-rich applications, no matter whether it’s a Web based app (using framework like Spring) or an iOS/Android gaming app. If you are really serious to become a Master of Java, check out the below resources that can make your Java programming journey a lot more smooth.
Learning over to you:
→ Object Oriented Java Programming
→ Java Programming Specialization
→ Building Cloud Services with Java Spring
→ Scalable Java Microservices with Spring Boot
→ Build Your First Android App (Project-Centered Course)