重排序是指编译器和处理器为了优化程序性能对指令序列进行重新排序的一种手段.
编译器和处理器在重排序时,会遵守数据依赖性; 编译器和处理器不会改变存在数据依赖关系的两个操作的执行顺序.当然,这里所说的数据依赖性是指单个处理器中执行的指令序列和单线程中执行的操作,不同处理器之间和不同线程之间 数据依赖性不被编译器和处理器考虑.
as-if-serial语义就是不管怎么重排序 ,程序的执行结果不能改变.
示例:
double pi = 3.14 ; //A操作
double r = 1.0 ; //B操作
double area = pi * r * r ; //C操作
A和C有依赖关系,B和C也有依赖关系,因此在最终执行的指令序列中C不能排列A,B前面,但是A,B之间没有依赖关系,有可能产生指令的重排序.JMM(java内存模型)认可这种重排序;
多线程性况下的示例:
public class ReOrderDemo {
int a = 0;
boolean flag = false;
public void write() {
a = 1; //1
flag = true; //2
}
public void read() {
if (flag) { //3
int i = a * a; //4
System.out.println(i);
}
}
}
假设两个线程A,B来操作,A执行写write()方法,随后B执行read()方法,那么B线程一定能看A线程对a的写入吗? 答案:不一定.
注意:flag只是一个标识符.
由于操作1,操作2没有依赖关系,所以编译器和处理器可以对这两个操作产生重排序; 同样,操作3,操作4没有依赖关系,所以编译器和处理器可以对这两个操作产生重排序;
我们来看看操作1,操作2做了重排序可能产生的一种时序情况.
这种情况下,B线程就读到了A写入前的数据了.....
日拱一卒无有尽,功不唐捐终入海