在多核处理器的环境下:编译器可能改变两个操做的前后顺序;处理器可能不是彻底依照程序的目标代码所指定的顺序执行命令;一个处理器执行的多个操做,在其余处理器的角度来看,其顺序可能与目标代码所指定的顺序不一致。这种现象就叫重排序。java
重排序类型 | 含义 |
---|---|
LoadLoad重排序 | 该重排序指一个处理器上前后执行两个读内存操做L1和L2,其余处理器对这两个内存操做的感知顺序多是L2——>L1,即L1被重排序到L2以后。 |
StoreStore重排序 | 该重排序指一个处理器上前后执行两个写内存操做W1和W2,其余处理器对这两个内存操做的感知顺序多是W2——>W1,即W1被重排序到W2以后。 |
LoadStore重排序 | 该重排序指一个处理器上前后执行读内存操做L1和写内存操做W2,其余处理器对这两个内存操做的感知顺序多是W2——>L1,即L1被重排序到W2以后。 |
StoreLoad重排序 | 该重排序指一个处理器上前后执行写内存操做W1和读内存操做L2,其余处理器对这两个内存操做的感知顺序多是L2——>W1,即W1被重排序到L2以后。 |
内存重排序与具体的处理器微架构有关,基于不一样微架构的处理器所容许的内存重排序是不一样的,这里再也不阐述。编程
对于编译器,JMM的编译器重排序规则会禁止特定类型的编译器重排序缓存
对于处理器重排序,JMM的处理器重排序规则会要求Java编译器在生成指令序列时,插入特定类型的内存屏障指令,经过内存屏障指令来禁止特定类型的处理器重排序。安全
数据依赖性: 若是两个操做访问同一个变量,且这两个操做中有一个为写操做,此时这两个操做之间就存在数据依赖性。数据依赖分为下列3种类型: 1.写后读:a=1;b=a; 2.写后写:a=1;a=2; 3.读后写:a=b;b=1;
为了遵照as-if-serial语义,编译器和处理器在重排序时,会遵照数据依赖性,编译器和处理器不会改变存在数据依赖关系的两个操做的执行顺序。由于这种重排序会改变执行结果。
不一样处理器之间和不一样线程之间的数据依赖性不被编译器和处理器考虑。多线程
在单线程程序中,对存在控制依赖的操做重排序,不会改变执行结果(这也是as-if-serial语义容许对存在控制依赖的操做作重排序的缘由);但在多线程程序中,对存在控制依赖的操做重排序,可能会改变程序的执行结果。架构
当操做1和操做2重排序时
当操做3和操做4重排序时
重排序在这里破坏了多线程程序的语义!并发
经过加锁同步可解决该问题
性能
参考资料:
1.Java并发编程的艺术(方腾飞 魏鹏 程晓明 著)
2.Java多线程编程实战指南(黄文海 著)优化