Java内存模型允许编译器和处理器对指令重排序以提高运行性能,并且只会对不存在数据依 赖性的指令重排序。
然后我们先来了解数据依赖性:
int a=l;
int b=2;
int c=a+b;
这里由于变量C的值依赖于a和b的值,所以不会进行重排序,即不会变成:
int c=a+b;
int a=l;
int b=2;
这样的顺序。
然后再来看最前面的程序:
if (ready) {
System.out.println(num + num);
}
num = 2;
ready = true;
由于在两个线程中,所以这上面三个步骤是没有数据依赖性的。
所以在写线程中,它不一定会执行num=2后再让ready=true;
有可能会ready=true后再运行num=2;
如果是后面这种情况的话,读线程就可能先读到ready为true,然后默认num=0,所以直接输 出0+0=0;然后cpu又继续运行num=2;此时会再输出2+2=4的这种情况。
所以,这就是指令重排序带来的灾难。 但是,你们运行上面的程序估计很难运行出0的情况,因为带有很大的不确定性。所以自己理 解了就好。
Java为了避免发生这种情况,可以使用volatile修饰上面的ready,这样ready前面的操作 比如num=2就不会被重排序到ready后面。这样就不会发生前面的这种情况。
写volatile变量时,可以确保volatile写之前的操作不会被编译器重排序到volatile写之后。读volatile变量时,可以确保volatile读之后的操作不会被编译器重排序到volatile 读之前。
Was this helpful?
0 / 0