博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java 虚拟机指令重新排序
阅读量:7281 次
发布时间:2019-06-30

本文共 2044 字,大约阅读时间需要 6 分钟。

指令重排序是JVM为了优化指令,提高程序运行效率,在不影响单线程程序执行结果的前提下,尽可能地提高并行度。编译器、处理器也遵循这样一个目标。注意是单线程。多线程的情况下指令重排序就会给程序员带来问题。

是为了保证单线程的运行效率,可以进行指令优化,不影响单线程的执行效果

但是指令重排在多线程之中会出现问题

JVM指令重排导致Singleton双重锁定出错

public class Singleton {  private static Singleton instance = null;  private Singleton() { }  public static Singleton getInstance() {     if(instance == null) {        synchronized (Singleton.class) {            if(instance == null) {                instance = new Singleton();  //非原子操作            }        }     }     return instance;   }}

看似简单的一段赋值语句:instance = new Singleton();,其实JVM内部已经转换为多条指令:

memory = allocate(); //1:分配对象的内存空间

ctorInstance(memory); //2:初始化对象

instance = memory; //3:设置instance指向刚分配的内存地址

但是经过重排序后如下:

memory = allocate(); //1:分配对象的内存空间

instance = memory; //3:设置instance指向刚分配的内存地址,此时对象还没被初始化

ctorInstance(memory); //2:初始化对象

可以看到指令重排之后,instance指向分配好的内存放在了前面,而这段内存的初始化被排在了后面,在线程A初始化完成这段内存之前,线程B虽然进不去同步代码块,但是在同步代码块之前的判断就会发现instance不为空,此时线程B获得instance对象进行使用就可能发生错误。

修改为如下的形式:

public class Singleton {    private static  volatile Singleton instance = null;    private Singleton() { }    public static Singleton getInstance() {    if(instance == null) {    synchronized (Singleton.class) {        if(instance == null) {            instance = new Singleton();            }        }    }        return instance;    }}

除了前面内存可见性中讲到的volatile关键字可以保证变量修改的可见性之外,还有另一个重要的作用:在JDK1.5之后,可以使用volatile变量禁止指令重排序。但是上面代码在jdk 1.5之前还是有问题的

注意,前面反复提到“从语义上讲是没有问题的”,但是很不幸,禁止指令重排优化这条语义直到jdk1.5以后才能正确工作。此前的JDK中即使将变量声明为volatile也无法完全避免重排序所导致的问题。所以,在jdk1.5版本前,双重检查锁形式的单例模式是无法保证线程安全的。

单例模式最还采用静态内部类的方式来实现,是最经典的也是保证线程安全的

package com.qqyumidi;public class SingleTon {    // 利用静态内部类特性实现外部类的单例    private static class SingleTonBuilder {        private static SingleTon singleTon = new SingleTon();    }    // 私有化构造函数    private SingleTon() {    }    public static SingleTon getInstance() {        return SingleTonBuilder.singleTon;    }    public static void main(String[] args) {        SingleTon instance = getInstance();    }}

 

转载于:https://www.cnblogs.com/kebibuluan/p/7761739.html

你可能感兴趣的文章
Tensorflow 线性回归预测房价实例
查看>>
UBUNTU tftp 配置
查看>>
利用runtime给系统类添加动态属性
查看>>
通讯录管理系统(C语言)
查看>>
PHP类与继承
查看>>
Proxifier突破代理服务器上网的限制
查看>>
Oracle(ERROR SP2-0642)
查看>>
反射加强(一)
查看>>
The class has no identifier property
查看>>
碰到的一些面试问题
查看>>
APICloud框架——总结一下最近开发APP遇到的一些问题 (二)
查看>>
python day04
查看>>
JVM的内存区域划分
查看>>
MySQL基础
查看>>
1595:Symmetry
查看>>
你应该知道的大数据领域12大动向
查看>>
R-CNN for Small Object Detection
查看>>
IF函数多个条件判断及嵌套
查看>>
代码搬移
查看>>
ajax请求code:200但是进入error函数
查看>>