单例模式 双重检查判断 不一定安全

单例模式 双重检查判断 不一定安全

双重检查判断

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;
    }
}

1)当线程A、B同时调用getInstance()方法,他们同时发现 instance == null成立(检查判断 1),同时去获取的Singleton.class锁
2)其中线程A获取到锁,线程B 处于等待状态;线程A会创建一个SingleTon实例,之后释 放锁
3)线程A释放锁后,线程B 被唤醒,线程B获取到锁,然后线程B检查
instance == null 不成立(检查判断2),不会再创建Singleton实例对象

编译优化后异常

我们认为的new Singleton()操作

  • 1)分配内存地址 M
  • 2)在内存 M 上初始化Singleton 对象
  • 3)将M的地址赋值给 instance 对象

JVM编译优化后可能的new Singleton()操作

  • 1)分配内存地址 M
  • 2)将M的地址赋值给instance变量
  • 3)在内存M上初始化 Singleton 对象
    在这里插入图片描述

异常发生过程(如上图,JVM创建new Instance()对象时先赋值再初始化)

1)线程A先执行getInstance()方法,当线程A在执行完变量的内存地址赋值(尚未初始化)时,发生线程切换,线程B获得CPU的执行权
2)线程B在执行第一个判断,发现 instance == null条件不成立,直接返回instance,但此时instance并没有初始化,此时访问instance对象的成员变量就可能发生空指针异常

解决

上述问题出现的本质原因是,JVM在编译时的执行重排序造成的,所以只要禁止指令重排序,就可以解决这个问题,所以需要在Singleton对象的成员变量instance前加volatile关键字

private volatile static Singleton instance;
发布了39 篇原创文章 · 获赞 19 · 访问量 1479

猜你喜欢

转载自blog.csdn.net/weixin_44222272/article/details/105180384
今日推荐