Java内存模型允许编译期和处理器对执行重排序以提高运行性能,并且只会对不存在数据依赖性的指令重排序。在单线程下重排序可以保证最终执行的结果与程序顺序执行的结果一直,但是在多线程下就会存在问题。
举例:
```Java
public class ReadThread extends Thread {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()){
if (ready){ // (1)
System.out.println(num+num); // (2)
}
System.out.println("read thread......");
}
}
public static class WriteThread extends Thread{
@Override
public void run() {
num =2; // (3)
ready = true; // (4)
System.out.println("writeThread set over......");
}
}
private static int num = 0;
private static boolean ready = false;
public static void main(String[] args) throws InterruptedException {
ReadThread readThread = new ReadThread();
readThread.start();
WriteThread writeThread = new WriteThread();
writeThread.start();
Thread.sleep(10);
readThread.interrupt();
System.out.println("main exit");
}
}
```
该段代码没有变量被声明为volatile,也没有采取同步措施,所以在多线程下存在共享变量内存可见性问题。这里先不谈内存可见性问题,因为通过把变量声明为volatile的本身就可以避免指令重排序问题。
在如上代码不考虑内存可见性问题的情况下不一定会输出4。由于(1)(2)(3)(4)之间不存在依赖关系,所以写线程的(3)(4)可能被重排序为先执行(4)再执行(3),那么执行(4)后,读线程可能已经执行的(1)操作,并在(3)执行前开始执行(2)操作,这时候输出的结果为0而不是4
重排序在多线程下会导致非预期的程序执行结果,而是用volatile修饰ready就可以避免重排序和内存可见性问题
摘自《Java并发编程之美》