Volatile keyword in java- difference between synchronized and volatile, 10 key points about volatile keyword, why volatile variables are not cached in memory


Contents of page :
  • volatile keyword?
  • What could be impact of not using volatile keyword?
  • Full program without synchronized or volatile, x and y are updated out of order >
  • How can be ensure that x and y are updated in order?
  • Full program using synchronized keyword, x and y are always updated in order>
  • Full program using volatile keyword, x and y are updated in order>
  • Volatile variable is not Cached in CPU memory >
  • 10 Key points about volatile keyword >


volatile keyword?
Using Volatile is java is very important topic, i will be covering this topic in lot of detail. Java allows threads to access shared variables. As a rule, to ensure that shared variables are consistently updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that enforces mutual exclusion for those shared variables.

If a field is declared volatile, in that case the Java memory model ensures that all threads see a consistent value for the variable.

What could be impact of not using volatile keyword?
We will create method1() which will be called repeatedly called by thread1 &
method2() which will be called repeatedly called by thread2.

static int x = 0, y = 0;
  
   static void method1() {
          x++; y++;
   }
   static void method2() {
          System.out.println("x=" + x + " y=" + y);
   }


then method two could occasionally print a value for x that is greater than the value of y, because neither synchronization nor volatile is used. The shared values of x and y might be updated out of order.

Full program without synchronized or volatile, x and y are updated out of order >
public class MyClass {
  
   static int x = 0, y = 0;
  
   static void method1() {
          x++; y++;
   }
   static void method2() {
          System.out.println("x=" + x + " y=" + y);
   }
  
   public static void main(String[] args) {
          Thread thread1=new Thread(){
                 public void run(){
                       for(int i=0; i<10;i++)
                              method1();
                      
                 }
          };
          Thread thread2=new Thread(){
                 public void run(){
                       for(int i=0; i<10;i++)
                              method2();
                      
                 }
          };
         
          thread1.start();
          thread2.start();
   }
}

/*OUTPUT
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
*/

NOTE: Output of this programs may not be that much conclusive because of unpredictable thread behaviour.

How can be ensure that x and y are updated in order?
We can use synchronized method or volatile keyword.

Few small questions>
Can we have volatile methods in java?
No, volatile is only a keyword, can be used only with variables.
Can we have synchronized variable in java?
No, synchronized can be used only with methods, i.e. in method declaration.



>Let’s use synchronized method first :

static  int x = 0, y = 0;
  
   static synchronized void method1() {
          x++; y++;
   }
   static synchronized void method2() {
          System.out.println("x=" + x + " y=" + y);
   }  



Using synchronized keyword will help updating x and y in order. Because of synchronization used against method we ensures that both methods are not called concurrently. Therefore, during execution of method2() x and y will be always equal.

Full program using synchronized keyword, x and y are always updated in order>
public class MyClass {
  
   static int x = 0, y = 0;
  
   static synchronized void method1() {
          x++; y++;
   }
   static synchronized void method2() {
          System.out.println("x=" + x + " y=" + y);
   }
  
   public static void main(String[] args) {
          Thread thread1=new Thread(){
                 public void run(){
                       for(int i=0; i<10;i++)
                              method1();
                      
                 }
          };
          Thread thread2=new Thread(){
                 public void run(){
                       for(int i=0; i<10;i++)
                              method2();
                      
                 }
          };
         
          thread1.start();
          thread2.start();
   }
}
/*OUTPUT
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
*/

NOTE: Output of this programs may not be that much conclusive because of unpredictable thread behaviour. But our aim was to show that method2() will always observe same value for x and y.


>Now, let’s use volatile keyword :

static volatile int x = 0, y = 0;
  
   static void method1() {
          x++; y++;
   }
   static void method2() {
          System.out.println("x=" + x + " y=" + y);
   }

      
This allows method1() & method2() to be executed concurrently, but assures that accesses to the shared values for x and y occur exactly as many times, and in exactly the same order, as they appear to occur during execution of the program text by each thread. Therefore, the shared value for y is never greater than that for x, because each update to x must be reflected in the shared value for x before the update to y occurs.
It is possible, however, that certain invocation of method2() might note a value for y that is much greater than the value noted for x, because method1() might be executed many times between the moment when method2() fetches the value of x and the moment when method2() fetches the value of y.

Full program using volatile keyword, x and y are updated in order>
public class MyClass {
  
   static volatile int x = 0, y = 0;
  
   static void method1() {
          x++; y++;
   }
   static void method2() {
          System.out.println("x=" + x + " y=" + y);
   }
  
   public static void main(String[] args) {
          Thread thread1=new Thread(){
                 public void run(){
                       for(int i=0; i<10;i++)
                              method1();
                      
                 }
          };
          Thread thread2=new Thread(){
                 public void run(){
                       for(int i=0; i<10;i++)
                              method2();
                      
                 }
          };
         
          thread1.start();
          thread2.start();
   }
}

/*OUTPUT
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
x=10 y=10
*/

NOTE: Output of this programs may not be that much conclusive because of unpredictable thread behaviour.

Volatile variable is not Cached in CPU memory >
Volatile members are never cached in CPU by jvm, they are always read from main memory i.e. from stack where variable lives.
It is possible for multiple CPU’s to exist on machine, so it is possibility that thread might cache different values in different CPU’s for same variable, so it’s important that value is not cached in CPU and always read from main memory.

Let’s discuss a scenario where non-volatile variable is used :
int x=0; // Let’s say we have variable x with value 0, in main memory value of x is 0 and in cache value of x is also 0.
x++; //increment done by thread1, so now in main memory  value of x is 1 but it might happen somehow that value is not updated in cache, so value of x in cache is still 0.
Now, lets say thread2 try to read that value, as value is cached, it will read read value from cache only, so value read of x will be 0 (but actual value of x is 1), which of course is a synchronization problem.

Let’s discuss a scenario where volatile variable is used :
int x=0; // Let’s say we have variable x with value 0, in main memory value of x is 0 and it’s not cached (as volatile variables are not cached).
x++; //increment done by thread1, so now in main memory  value of x is 1 and it’s not cached.
Now, lets say thread2 try to read that value, as value is not cached, it will read read value from main memory, so value read of x will be 1 (and actual value of x is 1), we have solved synchronization problem.



10 Key points about volatile keyword >

  1. Java allows threads to access shared variables. As a rule, to ensure that shared variables are consistently updated, a thread should ensure that it has exclusive use of such variables by obtaining a lock that enforces mutual exclusion for those shared variables. We can ensure such behaviour by using volatile keyword.

  1. If a field is declared volatile, in that case the Java memory model ensures that all threads see a consistent value for the variable.

  1. Volatile can be used as a keyword against the variable, we cannot use volatile against method declaration.
volatile  void method2() //it’s illegal
volatile int i; //legal

  1. In certain cases, Volatile keyword can be used as an alternate to synchronization in java, as all threads always have access to latest updated value.

  1. Using volatile is better than synchronization, as synchronization needs to block whole method (if used in method declaration) or block (if synchronization block is used), while volatile needs not to block any piece of code.

  1. Not Cached in CPU- Volatile members are never cached in CPU by jvm, they are always read from main memory i.e. from stack where variable lives.
It is possible for multiple CPU’s to exist on machine, so it is possibility that thread might cache different values in different CPU’s for same variable, so it’s important that value is not cached in CPU and always read from main memory.

  1. Volatile keyword must be used in multithreading environment, there is no use of using volatile keyword in non multi threading environment, it may cost us unnecessary performance issue as volatile keyword is not cached in memory by jvm.

  1. A compile-time error will occur if a final variable is declared volatile.

volatile final int x = 0; //The field x can be either final or volatile, not both.


  1. If variable which has been declared volatile, is a reference to object it may point to null as well,
volatile Integer i=null;  //it’s allowed.


      
  1. Performance issue - As volatile keyword is not cached in CPU, it is always read from main memory, so in terms of performance it’s always expensive to use volatile keyword.




/** JavaMadeSoEasy.com */


RELATED LINKS>

Volatile keyword vs synchronized>

Differences between synchronized and volatile keyword in detail


Race Condition >

Race condition in multithreading and it's solution



Consumer Producer problem solution using different techniques >
Solve Consumer Producer problem by using wait() and notify() methods in multithreading

solve Consumer Producer problem by using wait() and notify() methods, where consumer can consume only when production is over


How to solve Consumer Producer problem without using wait() and notify() methods, where consumer can consume only when production is over.




Object and class lock >

Acquiring object lock - synchronization blocks and methods- multiple threads may exist on same object but only one thread of that object can enter synchronized block/method at a time.
Acquiring lock on class, 2 Ways to acquire lock on class

Difference between object Lock and class Lock



Thread Pool, Thread local, Busy Spin >

Implement Thread pool in java

ThreadLocal in multithreading in java - methods and usage with program

Busy Spin - What is busy spin? Consumer Producer problem with busy spin and solution to busy spin.



No comments:

Post a Comment