在执行程序时,为了提高性能,处理器和编译器常常会对指令进行重排序;当然不能随意重排序,指令重排需要满足以下两个条件:
1.在单线程环境下不能改变程序运行的结果;
2.存在数据依赖关系的不允许重排序;
其实这两点可以归结于一点:happens-before规定的顺序不能改变,其他的JMM允许任意的排序;
从硬件架构上来说,指令重排序是指CPU采用了允许将多条指令不按照程序规定的顺序,分开发送给各个相应电路单元处理,而不是指令任意重排。
重排序分成三种类型:
1.编译器优化的重排序。编译器在不改变单线程程序语义放入前提下,可以重新安排语句的执行顺序;
2.指令级并行的重排序。现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序;
3.内存系统的重排序。由于处理器使用缓存和读写缓冲区,这使得加载和存储操作看上去可能是在乱序执行;
禁止指令的重排序
从Java源代码到最终实际执行的指令序列,会经过三种重排序;
但是,为了保证内存的可见性,Java编译器会在指令序列的适当位置插入内存屏障指令,来禁止特定类型的处理器重排序;
对于编译器的重排序,JMM会根据重排序规则禁止特定类型的编译器重排序;对于处理器重排序,JMM会插入特定类型的内存屏障,通过内存的屏障指令禁止特定类型的处理器重排序。
这里讨论JMM对处理器的重排序,为了更深理解JMM对处理器重排序的处理,先来认识一下常见处理器的重排序规则:
Mark:这里需要补充;
as-if-serial语义
不管怎么重排序(编译器和处理器为了提高并行度),(单线程)程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守as-if-serial语义;
本文还需补充
http://cmsblogs.com/?p=2116
https://blog.youkuaiyun.com/regemc/article/details/79879061