Java volatile修饰符的用法及作用详解版

要深刻理解volatile这个关键字的用法及作用,需要补充以下知识:

1、               内存访问操作/指令执行操作的乱序:假设每个CPU都分别运行着一个会触发内存访问操作的程序。那么对于这样一个CPU,其内存访问顺序是非常松散的,在保证程序上下文逻辑关系的前提下,CPU可能乱序执行内存操作。此外,编译器也可以将它输出的指令安排成任何它喜欢的顺序,只要保证不影响程序表面的执行逻辑。这里就涉及到了两次可能发生指令重排的情况:一个是编译的时候,由编译原理的知识知道,编译器会对代码进行优化,这一步就涉及到指令重排,当然,编译完成之后的目标代码中指令的顺序就是确定的,不同线程执行该代码的顺序是一样的;另一个就是CPU在执行具体的指令的时候,也会因为计算机当前的状态(比如寄存器的占用情况、ALU的使用情况,cup缓存层的存在等原因)的不同导致指令最终的执行顺序发生变化(实际上,cpu本身并不会对指令进行重排,它本身是按照编译后的顺序来执行指令的,只是由于执行不同的指令需要的时间长短不同,以及缓存层的存在,再加上CPU执行指令的流水线并不是串行化等因素,那么就有可能出现排在靠前位置的指令还没执行完,而排在靠后的指令已经执行完了的情况,这一情况就是所谓的CPU执行指令的乱序,具体原因后面会更详细地解释),尽管这个变化可能不影响最终结果的正确性。

2、               CPU指令执行乱序的原因:现在的CPU一般采用流水线来执行指令。一个指令的执行被分成:取址,译码,访存,执行,写回等若干个阶段。又因为指令流水线并不是串行化的,并不会因为一个耗时很长的指令在“执行”阶段呆很长时间,而导致后续的指令都卡在“执行”前的阶段上。相反,流水线中的多个指令是可以同时处于同一个阶段的,只要CPU内部相应的处理部件未被占满。比如说CPU只有一个加法器和一个除法器,那么一条加法指令和一条除法指令就可能同时处于“执行”阶段,而两条加法指令在“执行”阶段就只能串行工作。这样一来,乱序就可能产生了。比如一条加法指令出现在一条除法指令的后面,但由于除法的执行时间很长,在它执行完之前,加法可能就先执行完了。再比如两条访存指令,可能由于第二条指令中了cache(或其它原因)而导致它先于第一条指令完成。

3、               CPU执行指令乱序进一步说明:一般情况下,指令乱序并不是CPU在执行指令之前刻意去调整顺序,CPU总是顺序地去内存里取指令,然后将其顺序地放入指令流水线。但是指令执行时的各种条件,指令与指令之间的相互影响,可能导致顺序放入流水线的指令,最终乱序执行完成。这就是所谓的“顺序流入,乱序流出”。指令流水线除了在资源不足的情况下会卡住之外(如前所述的一个加法器应付两条加法指令),指令之间存在的相互依赖才是导致流水线阻塞的主要原因。当然,CPU的乱序执行并不是任意地乱序,而必须保证上下文依赖逻辑的正确性。比如:a++;b=f(a);由于b=f(a)这条指令依赖于第一条指令(a++)的执行结果,所以b=f(a);将在“执行”阶段之前被阻塞,直到a++的执行结果被生成出来。

另外一个CPU执行乱序的示例如下:

对于处理器A和处理器B都是按顺序分别执行A1和A2,以及B1和B2指令。以处理器A为例,为了提高执行效率,处理器执行A1只会将a=1写到缓冲区,紧接着就回执行A2指令,然后在适当的时候,才会将缓冲区中的数据回写主内存,即A3操作。所以尽管从处理器A的角度来看,执行顺序是A1->A2,但从内存操作实际发生的顺序来看确是A2->A1。因为A1操作只写了缓冲区,实际上直到处理器A执行完A3将缓冲区刷新到主存后,写操作A1才算真正执行完成。从这个角度也可以看出前面提到的,cpu不会刻意调整指令执行顺序,它本身是按照编译后的顺序来执行指令的,只是由于执行不同的指令需要的时间长短不同,以及缓存层的存在,再加上CPU执行指令的流水线并不是串行化的等因素导致cpu的最终执行效果是“顺序流入,乱序流出”。

4、               编译器指令重排(代码优化)的原理:如果两条有依赖关系(像刚刚列举的a++;b=f(a);)的指令挨得很近,后一条指令必定会因为等待前一条执行的结果,而在流水线中阻塞很久(这个“很久”是对计算机而言哈)。而编译器的乱序,作为编译优化的一种手段,则试图通过指令重排,在这两条指令之间插入其他指令,将这

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值