双重检查 单例模式

单例模式

/**
 * @description: 
 * 单例1 懒汉模式 double check
 * @author: brave.chen
 * @create: 2020-03-07 13:31
 **/
public class SingleDecl {
    private static  SingleDecl singleDecl;

    private SingleDecl() {
    }
    
    public static SingleDecl getInstance(){
        if(singleDecl == null){
            synchronized (SingleDecl.class){
                if(singleDecl == null){
                    singleDecl = SingleDecl.getInstance(); 
                }
            }
        }
        return singleDecl;
    }
}

上述代码并不是线程安全的
因为singleDecl = SingleDecl.getInstance();这部分代码并不是原子性的,
这个操作有很多步

   // 创建 Cache 对象实例,分配内存
       0: new           #5                  // class com/query/Cache
       // 复制栈顶地址,并再将其压入栈顶
       3: dup
    // 调用构造器方法,初始化 Cache 对象
       4: invokespecial #6                  // Method "":()V
    // 存入局部方法变量表
       7: astore_1
时序图

如果遇到这种情况 那么线程2就会返回null。

如何解决

/**
 * @description: 
 * 单例1 懒汉模式 double check
 * @author: brave.chen
 * @create: 2020-03-07 13:31
 **/
public class SingleDecl {
    private volatile static  SingleDecl singleDecl;

    private SingleDecl() {
    }
    
    public static SingleDecl getInstance(){
        if(singleDecl == null){
            synchronized (SingleDecl.class){
                if(singleDecl == null){
                    singleDecl = SingleDecl.getInstance(); 
                }
            }
        }
        return singleDecl;
    }
}

加了 volatile 关键字后
volatile 作用
正确的双重检查锁定模式需要需要使用 volatile。volatile主要包含两个功能。

保证可见性。使用 volatile 定义的变量,将会保证对所有线程的可见性。
禁止指令重排序优化。
由于 volatile 禁止对象创建时指令之间重排序,所以其他线程不会访问到一个未初始化的对象,从而保证安全性。

注意,volatile禁止指令重排序在 JDK 5 之后才被修复

你可能感兴趣的:(双重检查 单例模式)