Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble understanding the semantics of volatile in Java

Tags:

java

volatile

I've been reading up about the use of volatile variables in Java. I understand that they ensure instant visibility of their latest updates to all the threads running in the system on different cores/processors. However no atomicity of the operations that caused these updates is ensured. I see the following literature being used frequently

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

This is where I am a little confused. Here's a snippet of code which should help me better explain my query.

volatile int x = 0;
volatile int y = 0; 

Thread-0:                       |               Thread-1:
                                |
if (x==1) {                     |               if (y==1) {
     return false;              |                    return false; 
} else {                        |               } else {
     y=1;                       |                   x=1;
     return true;               |                   return true;
}                               |               }

Since x & y are both volatile, we have the following happens-before edges

  1. between the write of y in Thread-0 and read of y in Thread-1
  2. between the write of x in Thread-1 and read of x in Thread-0

Does this imply that, at any point of time, only one of the threads can be in its 'else' block(since a write would happen before the read)?

It may well be possible that Thread-0 starts, loads x, finds it value as 0 and right before it is about to write y in the else-block, there's a context switch to Thread-1 which loads y finds it value as 0 and thus enters the else-block too. Does volatile guard against such context switches (seems very unlikely)?

like image 587
HungryTux Avatar asked Feb 20 '23 02:02

HungryTux


2 Answers

So I think this question is a bit in the weeds, the gist is that volatile indicates that the value of the variable may change outside the scope of the current thread, and that its value must always be read before use.

In principle, the statement you're quoting is really saying that prior to replacing the value with the current thread, the value will be read.

Your example is a race condition, both threads may return true, neither may return true, or they may each return a different value -- the semantics of volatile won't define execution for your example (I'd encourage you to compile and run it and see that the output varies).

A common way to illustrate the behavior of volatile is to run two threads, where one thread updates shared state and to see what happens when the field is marked, and when it isn't:

class VolatileTest implements Runnable
{
        // try with and without volatile
        private volatile boolean stopRunning = false;

        public void triggerStop(){
             stopRunning = true;
        }

        @Override
        public void run(){
             while(!stopRunning);
             System.out.println("Finished.");
        }

        public static void main (String[] args) throws java.lang.Exception
        {
            final VolatileTest test = new VolatileTest();
            new Thread(test).start();
            Thread.sleep(1000);
            test.triggerStop() = false;
        }
}

In this example, failure to mark stopRunning as volatile can lead to the while loop continuing forever, as unless stopRunning is marked as volatile it's not required to read the value on each iteration.

like image 67
Mark Elliot Avatar answered Mar 04 '23 04:03

Mark Elliot


Semantics of Volatile

The problem you are referring to is a variation of Dekker’s Algorithm. With plenty of details on google on different implementations and details regarding it.

If two processes attempt to enter a critical section at the same time, the algorithm will allow only one process in, based on whose turn it is. If one process is already in the critical section, the other process will busy wait for the first process to exit. This is done by the use of two flags, flag[0] and flag[1], which indicate an intention to enter the critical section and a turn variable which indicates who has priority between the two processes.

Wikipedia covers the relevance of volatile with Dekker's Alogrithm

Volatile Information

But I found this article explains volatile perfectly in a single sentence.

If a variable is declared as volatile then is guaranteed that any thread which reads the field will see the most recently written value. (Lars Vogel, 2008)

Essentially, volatile is used to indicate that a variable's value will be modified by different threads. (javamex, 2012)

Massey University : Concurrency Volatile Lecture Slide

Massey Lecture Slide
(source: iforce.co.nz)

Source: Professor Hans W. Guesgen

If you don't yet understand volatile look into how atomicity works.

like image 21
classicjonesynz Avatar answered Mar 04 '23 05:03

classicjonesynz