今天在系统的学习Volatile,看到一个例子,运行起来会死循环,而加了一个Volatile就不会,然后引出结论 ----- Volatile可以使线程回写主存。很多教学视频用这个例子来教学。
我一看,不对劲。因为像例子里面的代码造成的死循环,在我几年的开发过程中,是没有遇到过的。其次,据我所知,在没有加Volatile的情况下,线程的内存不存在不回写的情况。之所以会线程不安全是因为线程的内存没有实时与主存同步,而加了Volatile可以保证线程可见性。
来看死循环具体的实现代码:
public class Main {
private boolean flag = false;
public static void main(String[] args) throws UnsupportedEncodingException {
Main main = new Main();
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(11111);
while(!main.flag) {
}
System.out.println(22222);
}
}).start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(33333);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
main.flag = true;
System.out.println(44444);
}
}).start();
}
}
如上述代码,会导致线程一死循环。然后加上Volatile就不会了。
但是,我看着就觉得不对劲,然后我试着在主线程去访问main.flag,发现也不会死循环了。再者,在while循环里,加上一行打印,也不会死循环了。
后面我查阅了一些资料,发现只要把jit优化去掉,就不会死循环了。
可以把上述代码,进行javac编译,然后 执行 java -Xint Main。(-Xint 的意思就是把jit优化去掉)
后面我再查阅了一些资料,发现 while(main.flag) 这一行代码,在Jit的优化下,会变成
boolean temp = main.flag;
while(temp){}
看来,这和可见性是一点关系都没有,而教学的人用这个人例子来证明可见性简直就是牛头不对马嘴。