设计模式学习---单例模式(双重检测锁以及volatile的必要性分析

引言

在学习创建型模式中的单例模式的时候,我们都会接触到双重检测锁实现的单例模式(饱汉模式),代码如下:

ublic class Singleton {
    /**
     * 饱汉模式(双重检测锁)
     */
    private Singleton(){};
    private static volatile Singleton instance = null;

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

可是为什么要使用volatile以及为什么要检测两次instance呢?

为什么使用Volatile

我们不妨先说一下volatile的作用

  • 防止指令重排
  • 指明被修饰的变量是不安全的,每次都必须到内存中读取

在单例模式中,我们使用volatile是为了防止指令重排,想象一下这种情况:当实例还没有创建的时候,线程A获得了synchronized锁,创建对象,虽然synchronized锁保证了操作的原子性,但是没有保证指令重排的正确性,如果构造函数中的操作很多,这个时候就可能出现instance已经被赋值了,但是还没有实例化完,这个时候如果线程B进入了,判断(instance==null)的时候就会误以为instance存在,直接返回,造成错误。

为什么要校验两次

想象一下这种情况:有两个线程同时通过了第一次判断instance==null,假设线程B获得了锁,此时线程A就处于等待状态。当线程B创建完实例之后,线程A可以获得这把锁,如果在这里没有第二次判断的话,线程A也会创建一个实例,这明显就与单例模式的初衷不符。

以上是我的个人理解。

你可能感兴趣的:(设计模式学习---单例模式(双重检测锁以及volatile的必要性分析)