🎊 双检锁/双重校验锁(DCL,即 double-checked locking)详细解析

双检锁/双重校验锁(DCL,即 double-checked locking)详细解析

1、介绍

单例模式是最常用的设计模式,并且双锁单例模式也是面试的常考题目。本文详细介绍了双锁单例模式,并总结了双锁单例模式的三个常考问题。

public class Singleton {

private volatile static Singleton instance;

private Singleton() {

}

public static Singleton getInstance() {

if (instance == null) {

synchronized (Singleton.class) {

if (instance == null) {

instance = new Singleton();//erro

}

}

}

return instance;

}

public static void main(String[] args) {

Singleton.getInstance();

}

}

2、提出问题

为什么双重检验 (即为什么使用了两个if语句)为什么加双锁(即为什么同时使用了synchronized关键字和volatile关键字)JDK版本为什么要大于1.5

2.1 为什么双重检验

public static Singleton getInstance() {

if (instance == null) {//线程1,2同时到达,均通过(instance == null)判断。

// 线程1进入下面的同步块,线程2被阻塞

synchronized (Singleton.class) {

if (instance == null) {//线程1执行发现instance为null,初始化实例后,释放锁。

// 线程2进入同步块,此次instance已经被初始化。无法通过if条件,避免多次重复初始化。

instance = new Singleton();

}

}

}

return instance;

}

执行双重检测是因为,如果多个线程通过了第一次检测,此时因为synchronized,其中一个线程会首先通过了第二次检测并实例化了对象,剩余的线程不会再重复实例化对象。这样,除了初始化的时候会加锁,后续的调用都是直接返回,解决了多余的性能消耗。

小结:

外层判断:完成实例化后,之后的线程就不需要再执行synchronized等待,提高效率。内层判断:防止多次实例化。

2.2 为什么加双锁

if (instance == null) {

instance = new Singleton();//erro

}

如果不使用volatile关键字,隐患来自于上述代码中注释了 erro 的一行,这行代码大致有以下三个步骤:

在堆中开辟对象所需空间,分配地址根据类加载的初始化顺序进行初始化将内存地址返回给栈中的引用变量

由于 Java 内存模型允许“无序写入”,有些编译器因为性能原因,可能会把上述步骤中的 2 和 3 进行重排序,顺序就成了

在堆中开辟对象所需空间,分配地址将内存地址返回给栈中的引用变量(此时变量已不在为null,但是变量却并没有初始化完成)根据类加载的初始化顺序进行初始化

通过对比发现,关键变化在于有volatile修饰的变量,赋值后(前面mov%eax,0x150(%esi)这句便是赋值操作)多执行了一个“lock addl$0x0,(%esp)”操作,这个操作的作用相当于一个内存屏障(Memory Barrier或Memory Fence,指重排序时不能把后面的指令重排序到内存屏障之前的位置)。

小结:

这里简单解释一下,在putstatic操作之前设置内存屏障,保证之前的3步骤无法重排在2步骤之前。

2.3JDK版本大于1.5

volatile关键字的屏蔽指令重排的语义在JDK1.5中才被完全修复。JDK5 以及后续版本扩展了volatile语义,不再允许volatile写操作与其前面的读写操作重排序,也不允许volatile读操作与其后面的读写操作重排序。

🎈 相关推荐

2024年组织工作盘点·基层党建 | 严密组织体系 锻造战斗堡垒
🏷️ office365用不了怎么回事

2024年组织工作盘点·基层党建 | 严密组织体系 锻造战斗堡垒

📅 07-16 👀 9833
2024年组织工作盘点·基层党建 | 严密组织体系 锻造战斗堡垒
🏷️ office365用不了怎么回事

2024年组织工作盘点·基层党建 | 严密组织体系 锻造战斗堡垒

📅 07-16 👀 9833
QQ群成员等级头衔怎么设置及积分规则说明
🏷️ 365bet正网开户

QQ群成员等级头衔怎么设置及积分规则说明

📅 07-01 👀 2459
烟民强烈推荐香烟TOP10排行榜 你的口粮上榜了吗
🏷️ office365用不了怎么回事

烟民强烈推荐香烟TOP10排行榜 你的口粮上榜了吗

📅 06-30 👀 1153
林肯口碑质量解析:车主真实反馈与车型对比
🏷️ 365bet限制

林肯口碑质量解析:车主真实反馈与车型对比

📅 07-01 👀 9237
【战地一】一文看懂如何筛选寻找服务器
🏷️ office365用不了怎么回事

【战地一】一文看懂如何筛选寻找服务器

📅 06-28 👀 6258