重排序概念
是一种优化
不影响单线程程序正确性的情况下,提升性能
为了性能, 物理上不能被禁止, 只能被逻辑上部分禁止,
Java是通过内存屏障实现逻辑上部分禁止的
术语
-
源码顺序
-
程序顺序
就是 字节码 顺序
-
执行顺序
实际执行 的顺序
-
感知顺序
某处理器感知到内存访问操作发生的顺序
指令重排序
源码和程序不一致或者 程序和执行 顺序不一致
JIT编译造成
比如new出来的对象还么有初始化完成就被使用了,
这是因为
1.分配实例所需空间, 获得一个指向该空间的引用objRef
2.初始化实例
3.把objRef复制给变量,继续
这3个顺序不一定, 可能先3再2
2种Java编译器
静态的javac: 不会重排
动态的JIT: 字节码->本地代码(机器码),在程序运行过程中介入,会重排
处理器造成(又叫乱序执行)
- 1.顺序读取
指令 按 程序顺序 被处理器读取
- 2,乱序执行
那条就绪 就会先被执行
- 3.执行结果 先存入 重排序缓冲器 ROB
- 4.顺序提交
ROB中的结果按程序顺序提交到寄存器 或者 内存
-
猜测执行
- 先执行if里面的语句得到结果 再执行if 条件的判断, false就把结果扔掉
- 问题是 有时候 原本的企图是 想先其他线程把其他事准备好, 再把if(这个标志)放开, 开始if{这里面的计算}
存储子系统重排序
是指感知顺序(某一处理器观察到的) 和其他顺序不一样
不是有什么被重排了, 而是一种现象
貌似串行语义
就是虽然重排了, 看起来和单线程下顺序的一样
这是重排必须达到的结果.
重排序必须遵守一些规则, 这些规则保证了这个结果.
但是只能保证单线程是这样.
存在数据依赖关系的语句不重排, 就能保证这个语义了
数据依赖关系:
存在依赖关系 就是2者的先后不允许被重排的,
-
1.WRE
后一句 操作数 是 前一句的执行结果
x=1;y=x;
-
2.RAW
前一句读取了一个变量 后一句 把这个变量变了
y=x;x=1
-
3.WAW
2句是对同一变量的写
x=1;x=2
控制依赖 不属于 数据依赖关系, 不然就不会有猜测执行了
保证内存访问的顺序性
只能逻辑上部分禁止重排序, 物理上禁止性能太低了
,Java是跨平台的语义, 禁止重排序是通过调用相应的指令
就是 内存屏障
我只要使用volatile synchronized就行了
网友评论