1

I read few articles on volatile Thread cache and found either it is too much brief without examples, so it is very difficult for beginner to understand.

Please help me in understanding below program,

public class Test {
    int a = 0;
    public static void main(String[] args) {        
        final Test t = new Test();
        new Thread(new Runnable(){
            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(){
            public void run() {
                while(t.a == 0) {}
                System.out.println("Loop done: " + t.a);
            }
        }).start();
    }

}

When I make a variable volatile and run my program then it stops after some time but when I remove volatile to a variable, then it goes on and my program is not stopping.

What I knew about volatile is "when variable is declared as volatile then thread will directly read/write to variable memory instead of read/write from local thread cache. if not declared volatile then one can see delay in updation of actual value."

Also, as per my understanding of refreshing the cached copy, I thought program will stop in some time but then why in above program it is continuing to run and not updating.

So when is Thread referring to its local cache starts referring to main copy or refresh its value with main copy value?

Please correct me if I am wrong in my understanding....

Please explain me with some small code snippet or link.

Jayesh
  • 6,047
  • 13
  • 49
  • 81

4 Answers4

9

when variable is declared as volatile then thread will directly read/write to variable memory instead of read/write from local thread cache. if not declared volatile then one can see delay in updation of actual value.

To begin with, the above statements are false. There are many more phenomena going on at the level of machine code which have nothing to do with any "thread-local variable caches". In fact, this concept is hardly applicable at all.

To give you something specific to focus on, the JIT compiler will be allowed to transform your code

while(t.a == 0) {}

into

if (t.a == 0) while (true) {}

whenever t.a is not volatile. The Java Memory Model allows any variable accessed in a data race to be treated as if the accessing thread was the only thread in existence. Since obviously this thread is not modifying t.a, its value can be considered a loop invariant and the check doesn't have to be repeated... ever.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • Actually it's not applicable at all if we go by the standard.. There's no mention of "read from memory" our anything like that at all in there. it's all about ordering guarantees! – Voo Feb 25 '14 at 16:26
  • Sure thing, however people still like to have some insight into what actually goes on and what is the motivation for JMM being what it is. On the other hand, OP may well need a primer in the JMM :-) – Marko Topolnik Feb 25 '14 at 17:13
  • Oh I was certain you know that all. You rightly refuted the claim about the whole cache thingie, I just feel it's very important to be very explicit about it. It's a nice lie and easy to understand but in the end that's not how it really works. Those little details are really important in the end I feel if you're going down to such a low-level concurrent programming :-) – Voo Feb 25 '14 at 17:37
  • It's true, this answer is more about the low level than about the JMM. For full understanding one should be familiar with both levels, but if one must choose just one, then it's certainly the JMM. However, the temptation to entertain the thoughts about what exactly is happening down below must be satisfied as well :) – Marko Topolnik Feb 25 '14 at 17:54
2

This may or may not be necessarily what is happening, but volatile also prevents certain reordering by the compiler.

For instance your code here

while(t.a == 0) {}
System.out.println("Loop done: " + t.a);

Can be reordered to

if(t.a == 0){
   while(true){
   }
}
System.out.println("Loop done: " + t.a);

This is called hoisting and is perfectly legal. Declaring it volatile will prevent this sort of ordering.

John Vint
  • 39,695
  • 7
  • 78
  • 108
  • 1
    I agree with hoisting but I think your example is wrong : in your second code, System.out.print called for every iteration, which does not have the same effect than the first code. Also, reordering and hoisting is not exactly the same thing, see http://stackoverflow.com/questions/11430095/are-hoisting-and-reordering-the-same-thing – Pierre Rust Feb 25 '14 at 12:14
  • You're right about system.out.println, I moved it below – John Vint Feb 25 '14 at 12:15
  • 1
    @PierreRust Hoisting is a kind of *code motion*, which could loosely be termed "reordering". – Marko Topolnik Feb 25 '14 at 12:16
0

If a variable is not declared volatile, whether it will be read from the cache or from the main copy is not predictable.

The cache has a limited size and the variable can get evicted from it for various reasons, like other variables occupying the cache. When this happens the main copy is read.

Enno Shioji
  • 26,542
  • 13
  • 70
  • 109
0

Marking a variable volatile is making sure changes to it are visible across threads.

In your code first thread changes the value of a and other thread sees this change and breaks out of loop.

Important point to note about volatile variable is value can change between last access and current access, even if compiler knows that its values is not being changed. (as @Marko Topolnik said) This stops the JIT compiler from doing optimizations like

while(t.a == 0) {}

into

if (t.a == 0) while (true) {}

knowing that a cant not change.

this talk offers very good explanation of these things. Jeremy Menson's talk on Java Memory Model@Google

Amit G
  • 2,293
  • 3
  • 24
  • 44