Java Volatile Keyword Working concept | what use of Volatile keyword in Multithreading

When a shared variable is  accessed by multiple threads , think about volatile keyword  .  When a field  is accessed by multiple threads , one thread’s changes to the field should be  visible to another thread. How it is possible ?.     The following tutorial covers about

  1. What volatile keyword indicates ?
   2. Why volatile keyword is required?
   3. When to use volatile modifier?
   4. How volatile works in java?  .

1. What volatile keyword indicates ?
  The volatile keyword indicates that a field can be  be modified by multiple threads that are executing simultaneously.  If a field is declared as volatile,  then the Java Memory Model  (JMM 133 , from java 5 )   ensures that all threads see a consistent value for the variable.

2. Why volatile keyword is required?

      Some of the following  reasons exist for  why the changes of a field  made by  one thread  is not communicated to another thread immediately  (i.e any thread  does not see the  most up-to-date value of  the field at any time)
               :
 a) Reordering of statements : Compiler optimizations are very important on modern platforms.  Instructions are  reordered by the compiler  to achieve maximum performance .   Due to this , instructions are  frequently not executed in the order it was written. At the same time , system needs to  maintain  as-if-serial semantics for individual threads. This works well in a single-threaded environment. i.e when a single thread executes, the result will appear as if all of the actions performed by that thread occur in the order they appear in the original program. But when multiple thread involves , the statement reordering done for a single thread  may be  out of order for other threads  which causes surprising results. Similarly  Processor and  caches  are allowed to reorder.

b) Thread may keep values in  local registers instead of shared memory whenever possible . So threads may see different values for shared variables.

c) On multiprocessor architectures, each processor may have own local caches to store shared variables  that are out of sync with main memory .

 One  solution to the above problem is Synchronization . Synchronization ensures both
    1. Visibility .  (any thread  sees the  most up-to-date value of  the field at any time)
    2. Mutual exclusion  (prevents methods / block of statements  from being executed concurrently)  . For more on synchronization , you can visit my earlier tutorial , Synchronization in java

 Another solution will be volatile modifier   It ensures the visibilty  of a  field  between threads i.e  any thread that reads the variable will see the last  written value   and it does not perform mutual exclusion  ie. it allows  methods /  block of codes to  be executed simultaneously by two or more threads.

3. When to use volatile modifier
                     
Some of the examples given below will give you clear  idea about when to use volatile
Example 1




class Reorder1 {

static   int value = 0;

static  boolean flag;



static   void one() {

    value = 100;

    flag = true;



       }



static void two() {

    if ( flag == true )

     System.out.println("Value " + value);



       }
In the above code , compiler is free to  reorder of statements as given below  as  statements value = 100; , flag = true; have  no dependency.



static   void one() {

    flag = true;

    value = 100;

 }

When the above code is executed by a single thread , calling  one() & two() methods  will give the output 100. When multiple threads execute the above methods simultaneously , the result may go wrong. When one thread execute the line flag=true , and another thread executes  the line
                       if ( flag == true )
                       System.out.println("Value " + value);
Now the result will be 0 .   One solution is to synchronize the above methods .   It  prevents method one and method two from being executed concurrently and also prevents reordering. Another solution is to declare  the field flag as   volatile   . Volatile read and write operations  can not be reordered with each other or  with respect to nonvolatile variable accesses

Example 2



 public static  PrimaryKeyGenerator getInstance()

   {

            if (instance == null)

       {

        synchronized(PrimaryKeyGenerator.class)

         {

           if (instance == null) 

             {

             instance = new PrimaryKeyGenerator();

               }

           }

        }

         return instance;      } 

The  above code is called double-checked locking idiom which implements singleton pattern suitable for  multithreaded environment and  also supports lazy initialization by  avoiding the overhead of synchronization.  But the above code does not work as expected due to  the reordering of  the  initialization of instance and the write to the instance field by the compiler . Suppose two threads execute the above code simultaneously .  The first thread  writes to instance variable first then  the object is constructed.  In the meantime , the second thread reads the instance field which is not null  before the first thread  finishes the construction of object.  So the second thread returns the incomplete object of  PrimaryKeyGenerator . We can fix  this problem with  Double-Checked Locking by declaring the instance field  volatile,  which prevents  reordering.

Example 3



class  WorkerOwnerThread

{

 // field is accessed by multiple threads.

 private static boolean  stopSignal;



  private static  void  doWork()

    {

        while (!stopSignal)

        {

           Thread t = Thread.currentThread(); 

           System.out.println(t.getName()+ ": I will work until i get STOP signal from my Owner...");

        }

         System.out.println("I got Stop signal . I stop my work");

    }



   private static   void stopWork()

    {

       stopSignal = true;

       Thread t = Thread.currentThread(); 

       System.out.println("Stop signal from " + t.getName()  );

    }

 

 

public static void main(String[] args) throws InterruptedException {



Thread workerThread = new Thread(new Runnable() {

      public void run() {

             doWork();    }

       });

workerThread.setName("Worker");

workerThread.start();



//Main thread

Thread.sleep(100);

stopWork();

}

}

The above code is another example for  when to use volatile modifier.  Two threads  Worker thread and Main thread are involved.  Worker thread starts and running continousely until it gets stop signal from the main thread.  This situation is a common use case for volatile.

  Under the new memory model (from JLS7), when one thread  writes to a volatile variable V, and thread B reads from V, any variable values that were visible to A at the time that V was written are guaranteed now to be visible to B. Here stopSignal is volatile variable. The changes made by the main thread to the stopSignal variable is communicated to Worker thread immediately.

 In the above code , if we synchronize  both methods doWork() and stopWork() instead of using volatile variable , if the worker thread starts first , then it  never stops . As synchronization performs mutual exclusion , when  the worker thread starts first  , the main thread never gets chance to update  stopSignal = true.  So declaring the stopSignal field as volatile is the  good solution.


4. How volatile works in java?

                                             1. The reads and writes of volatile fields  is made directly to main memory, instead of  to registers or the local processor cache.  This ensures that all the threads see the the most  recent written  value of  the field at all times        
               2. Fields that are declared volatile are not subject to compiler optimizations. ie. the reads and writes of volatile variables  can  not be reordered  with each other or  with respect to nonvolatile variable accesses.  A write to a volatile field happens-before every subsequent read of that same volatile.


Some of the key points about volatile keyword 

1. The volatile modifier is applied  to a field that is accessed by multiple threads without using the lock

2. Writes and reads of long and double variables declared as volatile are always atomic

2. The volatile keyword can not be applied to local variable

3.  final variable can not be a volatile.

4.  volatile modifier performs no mutual exclusion

5. Object variable declared as  volatile can be null .

6.  Reads and writes operations of volatile variables can not be reordered with each other  respect to each other or with respect to nonvolatile variable accesses

7. A write to a volatile field happens before every subsequent read of that same volatile

    Note : volatile is not the alternative to synchronization .

You can visit my another post for Difference between volatile and synchronized keyword 

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.