从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的情况

image.png

可以看到,在十个时钟周期内,非流水线CPU完整执行了两条CPU指令,执行新的指令前必须等待上一条指令执行完成

流水线CPU

接下来看流水线CPU的情况

image.png

可以看到,在十个时钟周期内,流水线CPU完整执行了指令1-6,还有指令7-10正在执行中

流水线CPU在执行指令方面会比非流水线CPU效率更高,现代CPU基本都采用流水线方式,但是流水线不是越长越好,流水线增加会导致单条指令的执行速度变慢

Java代码的CPU指令重排序

例如有如下Java代码

int c = a + b;
int d = f - e;

其对应的CPU指令执行时序如下

image.png

图中有些时钟周期对应的内容为×,比如ADD Rc, Ra, Rb这条指令对应的cycle5×,表示此时该指令在此处停顿了,原因了指令需要的数据Rb还没有被处理完成,当前指令无法获取到Rb的内容,这一停顿导致了后面所有指令都需要停顿一个时钟周期

CPU可以发现这种停顿,通过乱序执行部件(Out-of-Order core)对其进行优化,尽量指令的执行可以顺利进行而不用停顿:在这里CPU可能会将指令LW Rf, fLW Rc, c和前面的指令进行重排序,重排序后的执行时序如下

image.png

经过CPU重排序优化后,整个指令的执行时间从14个时钟周期变为了12个时钟周期

总结

CPU不是随随便便对指令进行重排序,而是真的会优化执行效率

参考资料