首页 > 其他 > 详细

单例模式的双重检查

时间:2020-07-12 11:27:54      阅读:62      评论:0      收藏:0      [点我收藏+]

单例模式的双重检查

双重检查

public class Singletone{
    private static Instance instance;

    public Instance getInstance(){
        if(instance == null){
            synchronized(Singletone.class){
                if(instance == null){
                    instance = new Instance();
                }
            }
        }
        return instance;
    }
}

问题
instance = new Instance();是由三个步骤组成的:

  • 为对象分配内存
  • 实例化对象
  • 将引用指向对应的内存地址

但是第2,3步可能发生指令重排列,导致先将引用指向一个未实例化对象的内存地址,然后再进行实例化对象。
若此时第二个线程进行第一个非空判断时,则为false,会直接返回还没有实例化对象的内存地址,从而可能产生异常。

解决

  • 禁止指令重排列
  • 允许指令重排列,但是其他线程“不可见”

方案一:基于volatile禁止指令重排列

public class Singletone{
    private volatile static Instance instance;

    public Instance getInstance(){
        if(instance == null){
            synchronized(Singletone.class){
                if(instance == null){
                    instance = new Instance();
                }
            }
        }
        return instance;
    }
}

在成员变量中加入volatile变量,禁止使用new创建对象时的指令重排列。

方案二:基于类初始化的解决方案

public class Singletone{
    private static class InstanceHolder{
        public static Instance instance = new Instance();
    }

    public static Instance getInstance(){
        return InstanceHolder.instance;
    }
}

JVM在类初始化阶段进行类的初始化。在初始化期间,JVM会获取一个锁,从而同步多个线程对同一个类的初始化。

第一个获得锁的线程会完成实例对象的创建,其他线程会直接获取创建的实例对象。

参考:

单例模式的双重检查

原文:https://www.cnblogs.com/truestoriesavici01/p/13287258.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!