0

Does volatile write assure that whatever writes (non-volatile / volatile writes) happens before it in one thread will be visible to other thread?

Will the following given code always produce 90,80 as output?

public class MyClass
{
    private boolean flag = false;
    private volatile int volatileInt = 0;
    private int nonVolatileInt = 0;
    public void initVariables()
    {
        nonVolatileInt = 90; // non-volatile write
        volatileInt = 80; // volatile write
        flag = true; // non-volatile write
    }
    public void readVariables()
    {
        while (flag == false)
        {}
        System.out.println(nonVolatileInt + ","+ volatileInt);
    }
    public static void main(String st[])
    {
        final MyClass myClass = new MyClass();
        Thread writer = new Thread( new Runnable()
        {
            public void run()
            {
                myClass.initVariables();
            }
        });
        Thread reader = new Thread ( new Runnable()
        {
            public void run()
            {
                myClass.readVariables();
            }
        });
        reader.start();writer.start();
    }
}

My concern is the method initVariables(). Isn't JVM has a freedom to reorder the code blocks in following way?:

flag = true;
nonVolatileInt = 90 ; 
volatileInt = 80;

And consequently, we get the output by the reader thread as : 0,0
Or, they can be reordered in the following way:

nonVolatieInt = 90;
flag = true;
volatileInt = 80;

And consequently, we get the output by the reader thread as : 90,0

Mac
  • 1,711
  • 3
  • 12
  • 26
  • @user2864740 however the other parts of the definition of _happens-before_ imply that if thread A writes volatile variable `v` and thread B reads `v` and sees the modification, then B is also guaranteed to see anything else that A did _before_ it wrote to `v`, including non-volatile writes to other variables. – Ian Roberts May 05 '14 at 11:08
  • 2
    @user2864740 the guarantee applies to program order - if B sees the change to `volatileInt` then it is also guaranteed to see the change to `nonVolatileInt` but it has no guarantees about `flag` - it may see the change or it may not. – Ian Roberts May 05 '14 at 11:13
  • @IanRoberts. So it means that the following reorderings `volatileInt = 80;nonVolatileInt = 90 ; flag = true` and `flag = true;volatileInt = 80 ; nonVolatileInt = 80` is not possible? In short, Whatever code is written above the volatile write (i.e `volatileInt=80`) can't be reordered with respect to the codes written above it or codes written below it .... – Mac May 05 '14 at 11:21
  • 1
    _from the point of view of a thread that has just performed a read of the `volatileInt`_, anything before the `volatileInt=80` in the first thread can't move after it, but things that appear after it might still appear to have moved before it. But _from the point of view of a thread that doesn't read `volatileInt`_ there are no guarantees at all - such a thread might see the write to `flag` but not the one to `nonVolatileInt` (in practice I suspect this is unlikely but the point is that it's not guaranteed). It's the volatile write/read pair that sets up the happens-before relationship. – Ian Roberts May 05 '14 at 11:55
  • Thanks @IanRoberts I am getting pretty clear picture now...+1 for this clear cut explanation. – Mac May 05 '14 at 12:26

1 Answers1

5

A volatile write ensures that writes already performed do not appear after this write. However to ensure you see this you need to perform a volatile read first.

And consequently, we get the output by the reader thread as : 90,0

Correct. However if you perform your reads correctly you cannot get 0, 80

0, 0 - ok
90, 0 - ok
90, 80 - ok
0, 80 - breaks happens before.

However, your reads do not ensure happens before behaviour as it doesn't perform the volatile read first.

System.out.println(nonVolatileInt + ","+ volatileInt);

This reads the non-volatile fields first, so you could see an old version of the non-volatile field and a new version of the volatile field.

Note: in reality, you are highly unlikely to see a problem. This is because caches invalidate a whole cache line at a time and if these fields are in the same 64-byte block, you shouldn't see an inconsistency.

What is more likely to be a problem is this loop.

 while (flag == false)
    {}

The problem is; the JIT can see your thread nevers writes to flag so it can inline the value. i.e. it never needs to read the value. This can result in an infinite loop.

http://vanillajava.blogspot.co.uk/2012/01/demonstrating-when-volatile-is-required.html

Eric Finn
  • 8,629
  • 3
  • 33
  • 42
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • Thanks so much for the quick input. So, does it mean that whatever codes are written before volatile write can't be reordered? – Mac May 05 '14 at 11:50
  • @Mac they can't be reordered to after. – Peter Lawrey May 05 '14 at 12:25
  • 1
    What I understood from your comment is that Whatever is written before the volatile write can't be reordered in such a way that they shift below the volatile write. But whatever written before the volatile write can be reordered among themselves. Am I right in my understanding? – Mac May 05 '14 at 12:34
  • 1
    @Mac: You got it right now, the volatile write is just a barrier for the writes made before it. And the easiest way to fix your code is to make `flag` `volatile` rather than `volatileInt` as it is the last thing you write and the first thing you read and even are waiting for. The only remaining issue would be the waste of CPU resources by polling a variable. – Holger May 05 '14 at 13:39
  • @PeterLawrey Why would JIT inline the flag? Does JIT doesn't anticipate the possibility that the flag might change in some part of code since it is not declared as final? – Mac May 05 '14 at 16:30
  • 1
    @Mac Non-volatile fields are not guaranteed to see an update in another thread, ever and there is significant optimisations the JIT can use if it detects a thread does not update a flag. There is nothing preventing the flag being inlined. – Peter Lawrey May 05 '14 at 16:35
  • Ahh that's interesting fact that you told u @PeterLawrey. One last doubt I have , Is it possible that the codes written below the volatile write can shift above the volatile write? – Mac May 05 '14 at 16:44
  • 1
    @Mac possible, from a read point of view, you may find that you can read all the writes at once. – Peter Lawrey May 05 '14 at 16:46
  • But from the read point of view , it is not possible that after I read the volatile variable, I won't see the changes in the non-volatile writes that are occurred before the volatile write. Right? – Mac May 05 '14 at 16:51
  • 1
    @Max Correct. The combination of a volatile write and a volatile read ensure you see all that was written up to the write and the reads are all consistent (no old values) – Peter Lawrey May 05 '14 at 16:54
  • Thank you so much @PeterLawrey.I am glad I got my doubt cleared from the expert :) – Mac May 05 '14 at 17:11
  • 2
    @Mac: beware that the entire thing only works if you can ensure that you read the `volatile` variable *after* the other thread has written to it. E.g. if `flag` is `volatile` your reading thread has to wait until it reads `true` from `flag`. Only then it can proceed reading the other variables knowing that it will read correctly all values that have been written before `flag` was set to `true`. – Holger May 06 '14 at 08:19