'Why doesn't volatile in java 5+ ensure visibility from another thread?
According to:
http://www.ibm.com/developerworks/library/j-jtp03304/
Under the new memory model, when thread A writes to a volatile variable V, and thread B reads from V, any variable values that were visible to A at the time that V was written are guaranteed now to be visible to B
And many places on the internet state that the following code should never print "error":
public class Test {
volatile static private int a;
static private int b;
public static void main(String [] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread() {
@Override
public void run() {
int tt = b; // makes the jvm cache the value of b
while (a==0) {
}
if (b == 0) {
System.out.println("error");
}
}
}.start();
}
b = 1;
a = 1;
}
}
b should be 1 for all the threads when a is 1.
However I sometimes get "error" printed. How is this possible?
Solution 1:[1]
Based on the extract from JCiP below, I would have thought that your example should never print "error":
The visibility effects of volatile variables extend beyond the value of the volatile variable itself. When a thread A writes to a volatile variable and subsequently thread B reads that same variable, the values of all variables that were visible to A prior to writing to the volatile variable become visible to B after reading the volatile variable.
Solution 2:[2]
You might want to check out a discussion thread on the concurrency interest mailing list on this question: http://cs.oswego.edu/pipermail/concurrency-interest/2012-May/009440.html
It seems like the problem is more easily reproduced with the client JVM (-client).
Solution 3:[3]
in My opinion,The Problem acurred due to Lack of Synchronization :
NOTICE : if b=1 heppens before a=1, and a is volatile while b is not, then b=1 actually updates for all threads only after a=1 is finished (according to the quate's logic).
what heppend in your code is that b=1 was first updated for the main process only, then only when the volatile assignment finished, all the threads b's updated. I think that maybe assignments of volatile are not working as atomic operations (needs to point far, and somehow update rest of refernces to act like volatiles) so this would be my guess why one thread read b=0 instead of b=1.
Consider this change to the code, that shows my claim:
public class Test {
volatile static private int a;
static private int b;
private static Object lock = new Object();
public static void main(String [] args) throws Exception {
for (int i = 0; i < 100; i++) {
new Thread() {
@Override
public void run() {
int tt = b; // makes the jvm cache the value of b
while (true) {
synchronized (lock ) {
if (a!=0) break;
}
}
if (b == 0) {
System.out.println("error");
}
}
}.start();
}
b = 1;
synchronized (lock ) {
a = 1;
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | sjlee |
| Solution 3 |
