20 November 2013

Volatile keyword explained in detail

We will now see what actually the "volatile" keyword is. Most of the people don't understand what volatile is and some gets it wrong. To that matter most experienced people in programming do fail in understanding this. You can rarely see people who can give a clear cut explanation of what "volatile" keyword is. Not easy to understand if you don't follow all the steps that we go through now.

First we need to understand how jvm executes the method. How jvm uses stack memory for method execution. So first i will provide a simple class with a method and a member variable and will show you how jvm does the method execution in that class. we need little bit understanding of memory allocation here to understand volatile.

Volatile.java

public class Volatile {

private static int count;

public static void main(String[] args) {
int local_var=23;
count=40;
int total=local_var+count;
System.out.println("The total is : "+total);
}
}

Have a careful look at the following diagram to understand how JVM executes the main method in the "Volatile.java".



 The above is the memory diagram once the execution of the main method is finish. So to understand how the main method has been executed by JVM, we take the step by step approach.

Once you try to run "Volatile.class" by using the command "java Volatile" the Volatile class is loaded into the class loader and immediately the class variable "count" is created on the heap inside Premgen memory with the default value as 0 and then the JVM immediately will start executing the main method.

So when JVM has to execute the main method (any method) first it creates stack memory for the method. The point is once the method execution is finish then the stack that is created for that method also gets destroyed.

 When JVM executes the first statement in main that is "int local_var=23;", the JVM creates a integer variable with name "local_var" with the value as 23 on the stack.

When JVM executes the second statement that is "count=40;", then the value of the class variable "count" changes to 40.

When JVM executes the third statement that is "int total=local_var+count;", it takes the value of "count" from the Premgen memory of the heap where the variable is and then adds it to the value of the local variable "local_var" and the final result of the addition will be assigned to the variable "total" on the stack as you can see in the diagram and then when it comes to the fourth statement it just prints the value of "total" on the console. Then it comes out of the main method and execution of the class "Volatile" is finished.

This is how the JVM executes the methods in the class. The total thing that needs to be understood is , variables declared inside the methods are called local variables and they get created only on the stack memory which is very specific to the method. Once the method execution is finish then the stack associated with that method also gets destroyed. The class variables are created on the Heap memory and they exist until the process gets terminated.

By this time i hope you have a clear understanding of memories and how JVM executes the methods by using the stack and heap memories.

Now if the basic understanding is clear we will jump into next step.

Look at the following code. I have done small modifications to the Volatile.java

Volatile.java
public class Volatile {

private static int count;

public static void main(String[] args) {
int local_var=23;
count=40;
int total=local_var+count;
System.out.println("The total is : "+total);
while(60 > count){
System.out.println(" I am in eternal loop");
}
}
}

If you carefully observe the above code the only change we made is , we added an while loop which is eternal.  When JVM starts the loop the "count" value is 40 and we are not increasing the value of count inside the loop. So the value of "count" is always 40 and "60" is always greater than "40" so the while loop is eternal. It never ends.

So the point here is not the eternal while loop. The main point is the condition the while loop is using. So what is the important thing in the condition. The important thing in the condition is the class variable "count". "count" is not a local variable. You know that very well. So what is great and what is the point that we need to understand is the frequency of the class variable being used inside the method. The usage of the class variable "count" is very high as the while loop condition is evaluated all the time.

The main point is "count" is being compared with "60" and the comparisons (validating the while condition) happening in a second  is too high. So in such situations when the frequency of the usage of class variables (or instance variables) is  very high the JVM takes a different approach in executing the methods. Now we will see what that different approach is and what is the difference between the prior execution and the execution that happens with the modifies "Volatile.java".

Look at the following diagram carefully to understand how the JVM executes the main method of the modified "Volatile.java"





Ok. Now if you carefully observe the above diagram there is a small change. You should be seeing the class variable "count" on stack and heap as well. So the class variable "count" exist in 2 places. Please don't get confused. I will be explaining this in detail so no need to worry or to get confused.

We will go step by step through the code to understand how JVM executed the method.

once you issue the command "java Volatile" to run the class Volatile the class variable count is created on the heap with the default value as 0;

Then JVM starts executing the main method. When it started with the main method the stack memory that is required for execution of the main method is created first and when JVM executes the first statement in the main method that is "int local_var=23;" , it creates the integer variable "local_var" with the value as 23 on the stack. once it is done then JVM moves to the next statement that is "count=40", so it changes the value of the variable "count" which is on the heap to 40. Then it moves to the next statement that is "int total=local_var+count;" so JVM gets the "count" value from the heap and adds it to the local variable "local_var" and the result will be assigned to the variable "total". So now the "total" variable is created on the stack with value 63. Then JVM moves to the next statement and finds a while loop. So it starts executing the loop. As the loop is eternal the jvm never comes out of the loop. Now here is the most interesting part. As the loop is eternal and happening at high frequency rates the condition gets evaluated at high frequency rates. When ever the condition of the while loop gets evaluated the value of the count has to get from heap and has to be compared against the value "60". So the catch point is the class variable "count" is being used at very high frequency rates so at this kind of instances the JVM takes slightly a different approach. Now at this kind of situations JVM instead of obtaining the value of "count" from the heap it just maintains a local copy of the class variable "count" on the stack to maintain the best execution speed. Here the intention of the  JVM is to reduce the time that it takes to get value of "count" from some other memory location. Now all the operations that has to happen on the class variable "count" happens on the local copy of "count" which is on the stack.

ok. I hope the concept is clear and you are able to understand the difference of the first execution and the 2nd execution that happens on the modified code of "Volatile.java" which has a while loop in it.

Now the most important point that should be understood is the JVM only maintains a local copy of the class or instance variables on the stack as long as the usage frequency of the class variable is very high inside the method. If the frequency gets reduced then it does not maintain a local copy. The local copy gets erased and before it is erased the value of the "count" on the heap is updated to the value of the local copy which is on the stack. So nothing to worry even when the local copy gets erased. After the local copy erased then the JVM obtains the value directly from the heap when required.

By this time anybody should be able to understand the clear distinction between the first and second execution situations and also the difference between how the JVM executed the method in first and second situations(how the memory is allocated for the variables).

Ok now it is time to prove our theory as explained above. Before we jump into the real time we make sure that you have the similar kind of environment where the examples that are going to be provide are tested on.

The run time environment we used:- 
java version "1.6.0_31"
Java(TM) SE Runtime Environment (build 1.6.0_31-b05)

Java HotSpot(TM) 64-Bit Server VM (build 20.6-b01, mixed mode)

I think even if it is higher version it should not be a problem but make sure that it is the "server vm" not the "client VM".

Fine to prove our theory we need to use Threads. As long as there is a single thread (main thread) it is not possible to prove what we just explained. Discussing about threads is the off topic and expected to have minimum knowledge on threads to understand the examples provided here after. We are going to work on examples which are similar to examples that i provided earlier when explaining the theory.

Example -1 :-

public class Volatile {  
  private static  int messageCount=0;
  
  public static void main(String[] args) throws Exception{  
      ReadMail rm=new ReadMail();  
      rm.start();  
      Thread.sleep(2000); //commenting this does make lot of difference. Here we are making the main

                                   //to sleep because we are giving jvm to acknowledge that the variable 

                                   //"messageCount" is frequently being used   

      SendMail sm=new SendMail(); 
      sm.start(); // This keeps incrementing the member variable "messageCount" intermittently. 

   } // end of main.  


   static class ReadMail extends Thread{ 

      @Override 
      public void run() { 
            int msgCount=messageCount; 
            while(msgCount < 5){  
                if(msgCount != messageCount){  
                      System.out.println("Local : "+msgCount); 
                      System.out.println("volatile : "+messageCount); 
                      msgCount=messageCount;  
                }// end of if  

            } // end of while  
      }
  
  }  // end of inner class.  

static class SendMail extends Thread{  

      @Override 
      public void run() {  
            int msgCount=messageCount; 
            while(messageCount < 5){ 
                System.out.println("send count : "+(msgCount+1));  
                  messageCount=++msgCount ;  
                try{  
                      Thread.sleep(500); 
                }catch(Exception e){  
                      e.printStackTrace();  
                }  
            } // end of while.  
      }
  
}  // end of inner class.

}// end of outer class.

if you check the output of the above code that is as below:-

send count : 1
send count : 2
send count : 3
send count : 4
send count : 5

The output is coming from the "sendMail" thread. This thread dies after 5 iterations of the while loop.

But the first thread "ReadMail" never dies and keeps poling the condition "msgCount != messageCount" inside the thread and the loop is eternal. The point here to understand is , When the "readmail" thread enters the loop the "messageCount" is 0. So the while loop goes eternal and keep poling the condition "msgCount != messageCount". The important point here that needs to be understood is, the second thread did changed the "messageCount" once in a while but the first thread's condition or expression never becomes true why?

if the jvm is always validating the expression of the first thread with the value of member variable "messageCount"  the condition should be true when ever the second thread changed the value of member variable. But as you can see the expression or the condition never validated as true even after the member variable value has changed .

Now try with the following example:- (with small modification of the Example 1)

Example 2 :-

public class Volatile {
  private static  int messageCount=0;

  public static void main(String[] args) throws Exception{
      ReadMail rm=new ReadMail();
      rm.start();
      Thread.sleep(2000); //commenting this does make lot of difference.
      SendMail sm=new SendMail();
      sm.start();
   } // end of main method

  static class ReadMail extends Thread{
        @Override
        public void run() {
              int msgCount=messageCount;
              while(msgCount < 5){
                  if(msgCount != messageCount){
                          System.out.println("Local : "+msgCount);
                          System.out.println("volatile : "+messageCount);
                          msgCount=messageCount;
                   } // end of if
                   try{
                       Thread.sleep(300);
                    }catch(Exception e){
                          e.printStackTrace();
                   }
              } // end of while
      } // end of run
  } // end of inner class

  static class SendMail extends Thread{
        @Override
        public void run() {
             int msgCount=messageCount;
            while(messageCount < 5){
                  System.out.println("send count : "+(msgCount+1));
                 messageCount=++msgCount ;
                  try{
                       Thread.sleep(1000);
                   }catch(Exception e){
                          e.printStackTrace();
                   }
              }  // end of while
        } // end of run
    } // end of inner class
} // end of outer class.
       

So the only modification in this code is we have added a "thread sleep" in the while loop of the "ReadMail" thread and also increased the sleep value of the "SendMail" thread. Ok now why we introduce "thread sleep" in the "readMail" thread is to reduce the frequency of poling the expression "msgCount != messageCount" on the "ReadMail" thread which obviously makes the jvm think the frequency of using the member variable is not so high. Then the output is as expected.

The following is the output:-

send count : 1
Local : 0
volatile : 1
send count : 2
Local : 1
volatile : 2
send count : 3
Local : 2
volatile : 3
send count : 4
Local : 3
volatile : 4
send count : 5
Local : 4
volatile : 5

So you can clearly see the expression of the "ReadMail" thread validated to true often and the output from the "ReadMail" thread for 5 times as the code is written that way.


ok coming back to the point of having local copies of the high frequency usage variables on stack. By this point you should be agreeing that the jvm maintains a local copy of the global variable when there is a high frequency usage inside the method (run is also a method).

Now how volatile helps in multithreading environment is, if you declare a "volatile" keyword for member variables which are shared between threads, it forces the jvm not to maintain "localcopies" even they have high frequency usage inside the method( run is also a method). To demonstrate this just add "volatile" keyword for the member variable in the first example code and after adding the volatile keyword, the first example behaves the same as second and you will be able to see the output as expected.

Hope this is helpful and gives clear understanding of what volatile keyword is. Cheers. Have a great day.

Summary:-
Basically the meaning of volatile is "highly sensitive" . changes it's form very fast. for example, volatile oils. Now in the context of java is also the same.


When you prefix "volatile" keyword with member variable, it just says to JVM not to maintain any local copies regardless of the situation. It also means the data could be shared among threads and there is high possibility of frequent changes by other threads so instead maintaining a local copy in some extraordinary situations always take the value directly from the heap( from the original variable). This is exactly what it means to JVM when volatile is prefixed with a member variable.
Post a Comment