12

As far as I know volatile write happens-before volatile read, so we always will see the freshest data in volatile variable. My question basically concerns the term happens-before and where does it take place? I wrote a piece of code to clarify my question.

class Test {
   volatile int a;
   public static void main(String ... args) {
     final Test t = new Test();
     new Thread(new Runnable(){
        @Override
        public void run() {
            Thread.sleep(3000);
            t.a = 10;
        }
     }).start();
     new Thread(new Runnable(){
        @Override
        public void run() {
            System.out.println("Value " + t.a);
        }
     }).start();
   }
}

(try catch block is omitted for clarity)

In this case I always see the value 0 to be printed on console. Without Thread.sleep(3000); i always see value 10. Is this a case of happens-before relationship or it prints 'value 10' because thread 1 starts a bit earlier thread 2?

It would be great to see the example where the behaviour of code with and without volatile variable differs in every program start, because the result of code above depends only(at least in my case) on the order of threads and on thread sleeping.

maks
  • 5,911
  • 17
  • 79
  • 123
  • I might be wrong here but AFAIK volatile keyword essentially tells the JVM that it cannot do any changes in the order of access to a variable, in an attempt to optimize. In other words you get safety (as in serial execution) at the cost of potential waits. I might be wrong tho so it would be interesting to see what others have to say on the matter. – posdef Jun 04 '12 at 21:06
  • possible duplicate of [Java: volatile guarantees and out-of-order execution](http://stackoverflow.com/questions/2441279/java-volatile-guarantees-and-out-of-order-execution) – Woot4Moo Jun 04 '12 at 21:09
  • 2
    The only thing volatile garuntees is that any thread that reads the variable will see the most recently written value. A volatile modifier is mainly used in mutiple threads. Java allows threads can keep private working copies of the shared variables (caches). These working copies need be updated with the master copies in the main memory. Volatile means the variable will live in the main memory _only_ not in the private working copies (caches). – Justin Jun 05 '12 at 02:49

6 Answers6

9

You see the value 0 because the read is executed before the write. And you see the value 10 because the write is executed before the read.

If you want to have a test with more unpredictable output, you should have both of your threads await a CountDownLatch, to make them start concurrently:

final CountDownLatch latch = new CountDownLatch(1);
new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            latch.await();
            t.a = 10;
        }
        catch (InterruptedException e) {
            // end the thread
        }
    }
 }).start();
 new Thread(new Runnable(){
    @Override
    public void run() {
        try {
            latch.await();
            System.out.println("Value " + t.a);
        }
        catch (InterruptedException e) {
            // end the thread
        }
    }
 }).start();
 Thread.sleep(321); // go
 latch.countDown();
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Wow nice idea with the `CountDownLatch`. Something like a "inversed" semaphore might also work. – Sebastian Hoffmann Jun 04 '12 at 21:17
  • even if I use CountDaownlatch to start threads simultenously, volotile doesn't work as I expected: I get different results per program invocation(note: my processor has 2 cores) – maks Jun 04 '12 at 22:23
  • 3
    @maks the problem with this example is it doesnt actually demonstrate a happens-before relationship with respect to `volatile a`. Volatile doesn't serve any purpose here. You would need to have the first thread set `t.a` then `countDown` while the other thread waits on `latch.await()` That creates a happens-before relationship between the two threads on the CountDownLatch. – John Vint Jun 04 '12 at 23:03
5

The happens-before really has to do with a write happens before any subsequent read. If the write has not occurred yet there really is no relationship. Since the write-thread is sleeping the read is executed before the write occurs.

To observe the relationship in action you can have two variables one that is volatile and one that is not. According to the JMM it says the write to a non-volatile variable before a volatile write happens before the volatile read.

For instance

volatile int a = 0;
int b = 0;

Thread 1:

b = 10;
a = 1;

Thread 2:

while(a != 1);
if(b != 10)
  throw new IllegalStateException();

The Java Memory Model says that b should always equal 10 because the non-volatile store occurs before the volatile store. And all writes that occur in one thread before a volatile store happen-before all subsequent volatile loads.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • 1
    +1 this is exactly what happens before means. For a more detailed discussion see: http://jeremymanson.blogspot.co.uk/2008/11/what-volatile-means-in-java.html for examples in code and an exploration of concurrency edge cases in code see here: https://github.com/shipilev/java-concurrency-torture – Nitsan Wakart Mar 08 '13 at 16:26
1

don't stick to the term 'happens-before'. it is a relation between events, used by jvm during R/W operations scheduling. at this stage it won't help you understand the volatile. the point is: jvm orders all R/W operations. jvm can order however it wants (of course obeying to all synchronize, lock, wait etc). and now: if variable is volatile then any read operation will see the result of latest write operation. if variable is not volatile then it is not guaranteed (in different threads). that's all

piotrek
  • 13,982
  • 13
  • 79
  • 165
  • The JVM cannot re-order writes made before a volatile write to be made after that write, that's what happens before means. They must happen before. This is part of the JMM and if that is broken you got a bug in your JVM. How you use it is a different matter. – Nitsan Wakart Mar 08 '13 at 16:33
  • yes, you're right. i just said that concept of 'happens-before' is not really helpful for a beginner for understanding meaning of volatile – piotrek Mar 08 '13 at 16:48
1

I've re-phrased (changes in bold fonts) the happens-before rule mentioned in the first sentence of your question as below so that it could be understood better -

"write of the value of a volatile variable to the main memory happens-before any subsequent read of that varible from main memory".

  • Also it is important to note that volatile writes/reads always happen to/from the main memory and NOT to/from any local memory resources like registers, processor caches etc.

The practical implication of the above happens-before rule is that all the threads that share a volatile variable will always see consistent value of that variable. No two threads see different values of that variable at any given point of time.

On the contrary, all the threads that share a non-volatile variable may see different values at any given point of time unless it is not synchronized by any other kind of synchronization mechanisms such as synchronized block/method, final keyword etc.

Now coming back to your question on this happens-before rule, i think u've slightly misunderstood that rule. The rule does not dictate that a write code should always happen (execute) before a read code. Rather it dictates that if a write code (volatile variable write) were to be executed in one thread before a read code in another thread then the effect of the write code should have happened in the main memory before the read code is executed so that the read code can see the latest value.

In the absence of volatile (or any other synchronization mechanisms), this happens-before is not mandatory, and hence a reader thread might see a stale value of non-volatile variable even though it has been recently written by a different writer thread. Because the writer thread can store the value in its local copy and need not have flushed the value to the main memory.

Hope the above explanation is clear :)

V.Vidyasagar
  • 633
  • 6
  • 13
0

piotrek is right, here is the test:

class Test {
   volatile int a = 0;
   public static void main(String ... args) {
     final Test t = new Test();
     new Thread(new Runnable(){
        @Override
        public void run() {
            try {
                Thread.sleep(3000);
            } catch (Exception e) {}
            t.a = 10;
            System.out.println("now t.a == 10");
        }
     }).start();
     new Thread(new Runnable(){
        @Override
        public void run() {
            while(t.a == 0) {}
            System.out.println("Loop done: " + t.a);
        }
     }).start();
   }
}

with volatile: it will always end

without volatile: it will never end

Kulik
  • 24
  • 3
0

From wiki:

In Java specifically, a happens-before relationship is a guarantee that memory written to by statement A is visible to statement B, that is, that statement A completes its write before statement B starts its read.

So if thread A write t.a with value 10 and thread B tries to read t.a some later, happens-before relationship guarantees that thread B must read value 10 written by thread A, not any other value. It's natural, just like Alice buys milk and put them into fridge then Bob opens fridge and sees the milk. However, when computer is running, memory access usually doesn't access memory directly, that's too slow. Instead, software get the data from register or cache to save time. It loads data from memory only when cache miss happens. That the problem happens.

Let's see the code in the question:

class Test {
  volatile int a;
  public static void main(String ... args) {
    final Test t = new Test();
    new Thread(new Runnable(){ //thread A
      @Override
      public void run() {
        Thread.sleep(3000);
        t.a = 10;
      }
    }).start();
    new Thread(new Runnable(){ //thread B
      @Override
      public void run() {
        System.out.println("Value " + t.a);
      }
    }).start();
  }
}

Thread A writes 10 into value t.a and thread B tries to read it out. Suppose thread A writes before thread B reads, then when thread B reads it will load the value from the memory because it doesn't cache the value in register or cache so it always get 10 written by thread A. And if thread A writes after thread B reads, thread B reads initial value (0). So this example doesn't show how volatile works and the difference. But if we change the code like this:

class Test {
  volatile int a;
  public static void main(String ... args) {
    final Test t = new Test();
    new Thread(new Runnable(){ //thread A
      @Override
      public void run() {
        Thread.sleep(3000);
        t.a = 10;
      }
    }).start();
    new Thread(new Runnable(){ //thread B
      @Override
      public void run() {
        while (1) {
          System.out.println("Value " + t.a);
        }
      }
    }).start();
  }
}

Without volatile, the print value should always be initial value (0) even some read happens after thread A writes 10 into t.a, which violate the happen-before relationship. The reason is compiler optimizes the code and save the t.a into register and every time it will use the register value instead of reading from cache memory, of course which much faster. But it also cause the happen-before relationship violation problem because thread B can't get the right value after others update it.

In the above example, volatile write happens-before volatile read means that with volatile thread B will get the right value of t.a once after thread A update it. Compiler will guarantee every time thread B reads t.a, it must read from cache or memory instead of just using register's stale value.

Jin Chen
  • 632
  • 1
  • 4
  • 10