The volatile Keyword in Java

Mohd Mohtashim Nawaz Oct 12, 2023
  1. The volatile Keyword in Java
  2. When Do We Use the volatile Keyword in Java
  3. Performance Advantage of the volatile Keyword in Java
  4. Use the volatile Keyword in Java
  5. Conclusion
The volatile Keyword in Java

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 the Thread class and overrides the run() method. Each thread sleeps for a 1-second duration.
  • MainClass.java: Main class is the most important class implementing the main() 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.