Java|面试官问我什么是JMM( 四 )
为了使指令更加符合CPU的执行特性 , 最大限度的发挥机器的性能 , 提高程序的执行效率 , 只要程序的最终结果与它顺序化情况的结果相等 , 那么指令的执行顺序可以与代码逻辑顺序不一致 , 这个过程就叫做指令的重排序 。
重排序的种类分为三种 , 分别是:编译器重排序 , 指令级并行的重排序 , 内存系统重排序 。 整个过程如下所示:
指令重排序在单线程是没有问题的 , 不会影响执行结果 , 而且还提高了性能 。 但是在多线程的环境下就不能保证一定不会影响执行结果了 。
所以在多线程环境下 , 就需要禁止指令重排序 。
volatile关键字禁止指令重排序有两层意思:
- 当程序执行到volatile变量的读操作或者写操作时 , 在其前面的操作的更改肯定全部已经进行 , 且结果已经对后面的操作可见 , 在其后面的操作肯定还没有进行 。
- 在进行指令优化时 , 不能将在对volatile变量访问的语句放在其后面执行 , 也不能把volatile变量后面的语句放到其前面执行 。
private static int a;//非volatile修饰变量private static int b;//非volatile修饰变量private static volatile int k;//volatile修饰变量private void hello() {
a = 1; //语句1
b = 2; //语句2
k = 3; //语句3
a = 4; //语句4
b = 5; //语句5
//以下省略...
变量a , b是非volatile修饰的变量 , k则使用volatile修饰 。 所以语句3不能放在语句1、2前 , 也不能放在语句4、5后 。 但是语句1、2的顺序是不能保证的 , 同理 , 语句4、5也不能保证顺序 。
并且 , 执行到语句3的时候 , 语句1 , 2是肯定执行完毕的 , 而且语句12的执行结果对于语句345是可见的 。
volatile禁止指令重排序的原理是什么
首先要讲一下内存屏障 , 内存屏障可以分为以下几类:
- LoadLoad 屏障:对于这样的语句Load1 , LoadLoad , Load2 。 在Load2及后续读取操作要读取的数据被访问前 , 保证Load1要读取的数据被读取完毕 。
- StoreStore屏障:对于这样的语句Store1 ,StoreStore ,Store2 , 在Store2及后续写入操作执行前 , 保证Store1的写入操作对其它处理器可见 。
- LoadStore 屏障:对于这样的语句Load1 ,LoadStore , Store2 , 在Store2及后续写入操作被刷出前 , 保证Load1要读取的数据被读取完毕 。
- StoreLoad 屏障:对于这样的语句Store1 ,StoreLoad , Load2 , 在Load2及后续所有读取操作执行前 , 保证Store1的写入对所有处理器可见 。
在每个volatile写操作的前面插入一个StoreStore屏障 , 后面插入一个SotreLoad屏障 。
大概的原理就是这样 。
面试官:讲得还不错 , 基本上都讲到了 , 时间也不早了 , 今天的面试就到这吧 , 回去等通知吧~
推荐阅读
- Java|淘宝商家要小心了!取消的“中差评”体系又回来啦!
- javascript|游戏开发之旅-JavaScript重新介绍
- Java|java多线程并发小demo
- Java|java程序猿如何才能走远,怎么做自己的职业规划
- 蚂蚁花呗|血亏!阿里P8轻易把总结了近一年的java高级特性笔记送人了
- jvm|清纯小学妹连续被三个大汉硬怼:JVM学成这样,还敢来面试?
- 百度|Java高级进阶多线程学习之路(七)ThreadLocal
- javascript|家里宽带是300M的,但是实际测速才2M应该这样维权。
- 社交|十一国庆过后,秋招Java岗,陆续收到字节/招银等offer
- Java|Java面试之基础问题答案口述整理