学习内容:
DCL实现单例模式
1.什么事DCL方法实现单例
因为构造方法的引用还是在引用getInstance
的时候,所以双重锁实现单例还是懒汉模式,为什么叫双重锁,双重锁有什么优势,下面我们基于代码来分析原因
/**
* 双重锁实现单例
*/
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
在懒汉模式中,我们对getInsane
这个函数进行了同步操作,这样操作有什么不好呢?
除了第一次引用getInstance
,之后的所有引用我们其实都会执行instance!=null,而这样加锁很明显对第一次引用比较有利,但对于后面的引用显得多余,造成了资源的浪费。所有我们做两次判空操作,第一次判空是减少不必要的同步,第二次判空保障是new Singleton()
是在instance
为null
下进行的
但是这样又引出了一个新的问题,众所周知instance = new Singleton();
大致做了三件事:
- 给Sinleton对象开辟内存空间
- 执行Singleton的构造方法
- instance指向分配的内存空间**(这时instance就已经不是null了)**
而有时程序在高并发执行过程中,2,3不会顺序执行,可能会先执行3,这会产生什么问题呢,如果进程A执行完3还没执行2就停下了,新的进程B可能在第一次判空时就把instance拿走使用了,这时还没执行2,程序肯定会报错。
为了解决这个问题,我们在定义instance时添加关键字volatile
这就保障了1,2,3的顺序执行