重排序
重排序的定义
重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。
重排序分3种类型
- 编译器优化的重排序。编译器再不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
- 指令级并行的重排序:现代处理器基本采用指令级并行技术,来将多条指令重叠执行。如果不存在数据依赖、处理器可以改变对应的机器指令的执行顺序
- 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
Java从源代码到最终实际执行的指令序列,会经历一下重排序

其中1操作属于编译器重排序、2和3属于处理器重排序。这些重排序可能会导致多线程程序出来内存可见性问题。对于编译器JMM的编译器重排序规则会紧张特定类型的编译器重排序、对于处理器重排序,JMM的处理器重排序规则会要 求Java编译器在生成指令序列时,插入特定类型的内存屏障(Memory Barriers,Intel称之为 Memory Fence)指令,通过内存屏障指令来禁止特定类型的处理器重排序。
JMM属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。
比如volatile 修饰符,通过添加内存屏障操作,(LoadLoad、StoreStore、LoadStore、StoreLoad)禁止指令重排序,保证内存可见性。
数据依赖性
如果两个操作访问一个数据变量,且存在写操作,测试两个操作就对数据产生了数据依赖性,分为一下三类
| 名称 | 代码实例 | 说明 |
|---|---|---|
| 写后读 | a=1; b=a; | 写一个变量之后,再读这个位置 |
| 写后写 | a=1; a=2; | 写一个变量之后,再写这个变量 |
| 读后写 | a=b; b=1; | 读一个变量之后,再写这个变量 |
以上操作,出现重排序两个操作的执行顺序,程序结果就会发送改变,所以这样的情况下不能进行重排序。
此处说明的数据依赖只针对单个处理器中执行的指令序列的单个线程中执行的操作, 不同处理器之间和不同线程之间的数据依赖性不被编译器和处理器考虑。
as-if-serial语义
as-if-serial语义的意思是:不管怎么重排序。单线程程序的执行结果不能被改变。编译器、返回语句和处理器必须遵守。
为了遵守语义,编译器和处理器都不会对存在数据依赖的操作进行重排序,

浙公网安备 33010602011771号