JUC:double-checked locking(DCL) 懒汉单例模式

文章目录

double-checked locking(DCL) 问题

  • 第一个if用于后续进入的线程,不用再获取锁来判断是否已经创建了对象。
  • 第二个if,为的是第一个进入的线程创建对象,以及防止卡在第一个if之后,获锁之前的线程在第一个线程已经创建对象的情况下,在获取锁后,判断不用创建对象,防止多次创建。

单例模式:

java 复制代码
public final class Singleton {
    private Singleton() { }
    private static Singleton INSTANCE = null;
    
    public static Singleton getInstance() { 
        if(INSTANCE == null) { 
            // 首次访问同步,而之后的使用就不用 synchronized,所以在此行前加了判断  
            synchronized(Singleton.class) {
                if (INSTANCE == null) { 
                    INSTANCE = new Singleton(); 
                } 
            }
        }
        return INSTANCE;
    }
}

特点:

  • 懒汉式实例化
  • 首次使用加锁,之后不用加锁

但是,看似完美的代码,其实并不对,因为第一个if判断并不在synchronized中,所以可能会发生指令重排问题。

synchronized可以保证原子、有序、可见性,但是有序性需要变量完全synchronized被保护,这里第一个if并不在sync中,所以是可能发生下述情况的。

也就是说synchronized只能保证临界区内的指令不和临界区外的指令发生重排序。

比如先给INSTANCE赋值了,但是还没有调用构造方法,这时线程切换,他以为你创建好了对象,然后返回对象直接开始使用,是不是就出现问题了,因为我们对象还没构造呢。

解决方法

给Singleton加volatile。

java 复制代码
public final class Singleton {
    private Singleton() { }
    private static volatile Singleton INSTANCE = null;
    
    public static Singleton getInstance() { 
        if(INSTANCE == null) { 
            // 首次访问同步,而之后的使用就不用 synchronized,所以在此行前加了判断  
            synchronized(Singleton.class) {
                if (INSTANCE == null) { 
                    INSTANCE = new Singleton(); 
                } 
            }
        }
        return INSTANCE;
    }
}

这样就是一个正确的代码了。

volatile作用

volatile作用:

可见性:

  • 写屏障(sfence)保证在该屏障之前对共享变量的改动,都同步到主存当中
  • 读屏障(lfence)保证在该屏障之后对共享变量的读取,加载的是主存中最新数据

有序性:

  • 写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
  • 读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前

只能保证读数据正确,不能保证原子性。

相关推荐
珊瑚里的鱼1 天前
手撕单例模式中的饿汉模式和懒汉模式,懒汉模式还要再多加一个C++11版本的
开发语言·c++·单例模式
韩曙亮1 天前
【Flutter】Dart 单例 ( 单例模式核心规则 | 饿汉式单例 | 懒汉式单例 | 极简空安全 懒汉式单例 | 工厂构造函数单例 )
flutter·单例模式·dart·饿汉式单例·懒汉式单例·空安全·空赋值
wunaiqiezixin3 天前
如何在C++中实现一个单例模式?
c++·单例模式
basketball6163 天前
设计模式入门:1. 单例模式详解 C++实现
c++·单例模式·设计模式
bugcome_com4 天前
阿里云OSS工具类完整设计与实现:基于.NET的静态单例模式实践
阿里云·单例模式·.net·oss
JAVA9654 天前
JAVA面试-并发篇 03-使用synchronized doublecheck实现单例有什么坑
java·单例模式·面试
HEADKON7 天前
司拉德帕失代偿期肝硬化及胆道梗阻患者禁止使用,肝酶升高需暂停药物
单例模式
IT空门:门主9 天前
Java 单例模式详解:7 种实现方式 + volatile 原理 + 反射与序列化问题
java·开发语言·单例模式
码农的小菜园10 天前
Java创建单例
java·开发语言·单例模式