JVM 编译之指令重排
来源:互联网 发布:php get请求 编辑:程序博客网 时间:2024/05/31 00:39
介绍 :
所谓的指令重排指的就是jvm在编译代码的时候 ,为了提高程序运行效率,在不影响单线程程序执行结果的前提下,对指令进行的排序,当然我们这里的是单线程,如果是在多线程中就会影响程序的结果了
可能你听了我的介绍 还是不明所以,到底什么是指令重排?,没关系,下面我们通过代码来理解到底什么是指令重排
1---> int a = 2 << 1; 2---> int b = 3 << 1; 3---> int result = a * b + 2333;
相信你看到这段简短的代码,也会知道这段代码的执行顺序,1 - > 2 -> 3,相信你会觉得这就是代码执行的顺序,但是在jvm中是不会这样执行的,这里我们可以用着三个变量的依赖关系来解释一下原因
这三个变量中 1 与 2没有依赖关系 3与 1和2 都有依赖关系,也就是说,没有依赖关系的两段代码即使我们将他们编译执行的顺序进行调换,这样也不会对代码的结果产生改变 也就是 上面的代码在jvm中实际上是 2 -> 1 -> 3
当然在单线程中JVM对代码进行指令重排并不会产生影响,但是在多线程中进行指令重排的话就会产生一些不确定的结果了,现在我们来看一下指令重排在多线程的一个经典的例子,单例模式,懒加载
public class DateBaseTools{ private static DateBaseTools instance = null; public static DateBaseTools getSingInstance() { if (instance == null) { synchronized (DateBaseTools.class) { instance = new DateBaseTools(); } } return instance; } public void action() { System.out.println(">>>>>>>>>>"); }}
再上面的懒加载模式中,我们要是在多线程并发中调用这个单例的话,就会因为JVM的指令重排造成一些不可预料的结果,下面我们来分析一下
看似简单的一段赋值语句: instance = new DateBaseTools();,但是很不幸它并不是一个原子操作,其实际上可以抽象为下面几条JVM指令:
memory =allocate(); //1:分配对象的内存空间 ctorInstance(memory); //2:初始化对象 instance =memory; //3:设置instance指向刚分配的内存地址
我们可以看出 第一条指令对第二条指令有依赖关系,但是第二条指令与第三条指令并没有依赖关系,所以根据JVM指令重排的规矩可以对第二条与第三条指令的执行顺序进行交换,这样看起来没有什么问题,但是在多线程中这样就会产生问题了
我们假定有两个线程,第一个线程调用单例模式的getSingInstance() 开始执行1 ->2 -> 3要是这个时候在JVM中执行的是 1 -> 3 ->2,也就是分配好内存空间后,为instance分配内存地址,这个时候线程二抢占cpu资源,执行getSingInstacne发现instance不为空 就会返回instance,这个时候返回的instanc还没进行初始化,肯定会报错了
解决方案
给单例类中引用的instance加上volatile关键字,volatile关键字有一个作用就是防止JVM对其进行指令重排序
在 volatile 变量的赋值操作后面会有一个内存屏障,大多数的处理器都支持内存屏障的指令。上面的代码在加上volatilc后getSingInstace操作必须在执行完 1-2-3 之后或者 1-3-2 之后,不存在执行到 1-3 然后取到值的情况。
- JVM 编译之指令重排
- JVM之指令重排分析
- JVM之指令重排分析
- JVM之指令重排分析
- JVM 指令重排
- 多线程之指令重排
- 并行编程之指令重排
- (八 附)java并发编程--JVM之指令重排分析
- JVM指令重排导致Singleton双重锁定出错
- 深入理解JVM 系列JVM运行机制 JVM内存模(volatile,指令重排)
- 深入理解JVM 系列JVM运行机制 JVM内存模(volatile,指令重排)
- JMM 指令重排
- JMM指令重排
- 指令重排的基本原则
- MMX指令集系列之三----数据饱和压缩与重排指令
- java虚拟机的指令重排和CPU的指令重排
- 指令重排与happens-before
- JMM Cookbook(一)指令重排
- 持续集成
- MAVEN 聚合、继承
- android学习之自定义dialog
- android之FrameLayout属性foreground
- jQuery EasyUI使用教程之格式化组合框项
- JVM 编译之指令重排
- MySQL四种事务隔离级的说明
- textView 弹出键盘上面添加完成按钮,并设置输入内容的格式。
- Ubuntu安装Fcitx以及Fcitx输入中文不显示候选词框的解决办法
- IOS(数字优先,字母其次进行排序)
- hibernate入门实例(一)(初学者)
- 关闭”xx程序已停止工作”提示窗口
- [js] BOM
- 几种加密方式