从volatile讲起
我们都知道Java中volatile
关键字有一个重要的作用:
- 禁止指令重排序:有时候CPU会对指令进行重排序来达到提高执行效率的目的
那么到底什么是指令重排序,为什么重排序之后就可以提高执行效率?我们一起来学习和探讨一下。
CPU指令的执行
一条CPU指令的执行阶段(这里只讨论五级指令流水线):
- IF(Instruction Fetch):取指令,从主存中将一条指令取到指令寄存器
- ID(Instruction Decoded):指令译码,按照预定格式对取回的指令进行拆分和解释
- EX(Execute):执行指令,实现指令的具体操作
- MEM(Memory Access):访问存储器取数据,根据指令,访问内存读取操作数用于运算或者将数据写入到存储器
- WB(Write Back):结果写回,将指令执行阶段运算结果写回存储器,如CPU寄存器,主存
非流水线和流水线CPU在10个时钟周期内分别可以执行的指令比较
非流水线CPU
首先来看非流水线CPU的情况
可以看到,在十个时钟周期内,非流水线CPU完整执行了两条CPU指令,执行新的指令前必须等待上一条指令执行完成
流水线CPU
接下来看流水线CPU的情况
可以看到,在十个时钟周期内,流水线CPU完整执行了指令1-6,还有指令7-10正在执行中
流水线CPU在执行指令方面会比非流水线CPU效率更高,现代CPU基本都采用流水线方式,但是流水线不是越长越好,流水线增加会导致单条指令的执行速度变慢
Java代码的CPU指令重排序
例如有如下Java代码
int c = a + b;
int d = f - e;
其对应的CPU指令执行时序如下
图中有些时钟周期对应的内容为×
,比如ADD Rc, Ra, Rb
这条指令对应的cycle5
为×
,表示此时该指令在此处停顿了,原因了指令需要的数据Rb
还没有被处理完成,当前指令无法获取到Rb
的内容,这一停顿导致了后面所有指令都需要停顿一个时钟周期
CPU可以发现这种停顿,通过乱序执行部件(Out-of-Order core)
对其进行优化,尽量指令的执行可以顺利进行而不用停顿:在这里CPU可能会将指令LW Rf, f
和LW Rc, c
和前面的指令进行重排序,重排序后的执行时序如下
经过CPU重排序优化后,整个指令的执行时间从14个时钟周期变为了12个时钟周期
总结
CPU不是随随便便对指令进行重排序,而是真的会优化执行效率
参考资料
- 《实战Java高并发程序设计》- 葛一鸣
- 指令流水线 - 维基百科
- 为什么CPU流水线设计的级越长,完成一条指令的速度就越快? - 知乎
- 处理器中的流水线技术 - 知乎
- CPU流水线的探秘之旅 - 博客园