The volatile Keyword in Java
-
The
volatile
Keyword in Java -
When Do We Use the
volatile
Keyword in Java -
Performance Advantage of the
volatile
Keyword in Java -
Use the
volatile
Keyword in Java - Conclusion
Java is a highly popular programming language, and we can easily understand by understanding Java why it has earned such a position in the programming community.
Java provides us with a large number of useful resources which we can use in our programs to write out our desired logic.
Java is useful for multipurpose programming problems, and one such programming problem is working with threads or the parallel execution of different logical programs.
This article will explore and understand the volatile
keyword in Java, its properties, and its usage in practical programming. We will understand when to use the volatile
keyword, its importance, and when and should not be used.
This article will also provide a basic example code to help you understand the volatile
keyword.
The volatile
Keyword in Java
You might have come across the parallel threads and the synchronized
keyword while working with Java. The volatile
keyword is similar to the synchronized
keyword, yet quite different.
The volatile
keyword is easy to understand and implement in our code and has a lesser runtime overhead than the synchronized
locking mechanism. However, the volatile
keyword is not as powerful as the synchronized
locking.
The volatile
keyword ensures that the changes made to a shared volatile
variable are reflected in all threads immediately. The synchronized
keyword is used to achieve the locking mechanism in Java, and the lock provides visibility and atomicity.
However, the volatile
keyword can only achieve visibility, not atomicity. Therefore, we can understand that the volatile
keyword can only be used in a very small number of cases.
For example, we can use it when the variable’s value is independent of all other variables and cases and even itself.
When Do We Use the volatile
Keyword in Java
As we have already seen, with the help of the volatile
keyword, the altered values of the shared variables are immediately reflected in all other threads. Therefore we use it while working with shared variables in threads.
When the synchronized
keyword is already available, you might ask why we use the volatile
keyword? However, the volatile
keyword is simpler to understand and performs better.
Therefore there are cases when we might want to use it. For example, when we have a large number of reading operations and a small number of write operations, we want to use the volatile
keyword for better performance.
Also, the volatile
keyword provides better scalability as it does not cause the thread block.
To better understand the situation where we can use the volatile
keyword safely and effectively, we should watch out for the following conditions.
- There should be no inter-dependence between the program’s current and other variables and states.
- The variable should not depend on itself.
Therefore, if our variable is completely independent even from itself, we can use our code’s volatile
keyword.
However, we often encounter situations that do not satisfy either the first or the second condition or both of the conditions. Therefore, the use of volatile
keywords is very restricted.
Note a very subtle mistake that many programmers make. Many times programmers tend to consider increment operators as a single operation.
However, the increment operator (or decrement operator) consists of multiple operations and happens in multiple stages. Therefore, we should not use the volatile
keyword in such cases.
Performance Advantage of the volatile
Keyword in Java
While the volatile
keyword is simple and easy to use, it performs better than the locking mechanism. In some situations, it is seen that the volatile
performs much better than the synchronized
.
However, the case is not that simple. When we have Java Virtual Machine (JVM), it is difficult to judge the performance of the two keywords correctly.
It is because JVM performs optimizations, and sometimes the locking is not needed, and JVM removes it in code optimization. However, the volatile
reads are generally observed to be very good at performance and comparable to the normal reads.
However, the volatile
writes are much more costly than normal ones. On the other hand, volatile
writes are always cheaper than acquiring locks.
Therefore, we should consider this performance comparison between the volatile
keyword and the synchronized
locking mechanism.
We have already discussed another performance advantage of the volatile
: it does not cause the thread blocking and is much better at scalability. It’s yet another reason for using the volatile
keyword.
Use the volatile
Keyword in Java
We will understand how to use the volatile
keyword in our Java code in the following code.
sharedObj.java
public class sharedObj {
volatile boolean flag;
}
ThClass.java
public class ThClass extends Thread {
public sharedObj obj;
public ThClass(sharedObj obj) {
this.obj = obj;
}
@Override
public void run() {
super.run();
while (true) {
if (this.obj.flag)
this.obj.flag = false;
else
this.obj.flag = true;
System.out.println(obj.flag);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
MainClass.java
import java.util.*;
public class MainClass {
public static void main(String[] args) {
sharedObj obj = new sharedObj();
ThClass th1, th2;
th1 = new ThClass(obj);
th2 = new ThClass(obj);
th1.run();
th2.run();
}
}
In the Java program given above, we have created three different classes. These classes are explained as follows.
sharedObj.java
: We have declared a volatile shared variable shared among threads in this class.ThClass.java
: This class is used to create threads. It extends theThread
class and overrides therun()
method. Each thread sleeps for a 1-second duration.MainClass.java
:Main
class is the most important class implementing themain()
method from where the execution starts. We have created two threads and passed a shared object as a parameter through the constructor.
The output of this Java program is shown below.
true
false
true
false
true
false
Note that this code runs for infinite time, and to stop it, you have to stop its execution manually. (For example, by pressing CTRL+C on Linux).
Conclusion
In this article, we have understood the volatile
keyword, its advantages and disadvantages, and when we can use it. Although the volatile
keyword is not as powerful as the synchronized locking mechanism, it is still used in practice.
We still use the volatile
keyword because it is much easier to understand and implement in the code, has better performance than locks, and is easier to scale as it does not lock the threads.
However, you should always check the conditions with care while using the volatile
keyword in your code so that you do not commit an unforeseen error.
This article has mentioned simple steps to check whether the volatile
keyword is applicable or not; check using those steps to know whether the volatile
is applicable in your code or not.
It would help choose between the synchronized locking mechanism and the volatile
keyword.