问题
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.
回答1:
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.
回答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.
回答3:
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.
回答4:
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
来源:https://stackoverflow.com/questions/22013353/when-java-refresh-thread-cache-to-actual-copy