DCL单例模式中的volatile解析(含图解)

对不清楚单例模式的小伙伴可以参考我的另一篇文章:

八种单例模式使用,最全单例模式!(优缺点分析)

在Java中单例模式存在这么一种情况如下:

/**
 * DCL双锁校验
 * 线程安全
 * volatile关键字用于防止指令重排序
 */
class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {}

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

        }
        return singleton;
    }
}

这种单例模式被称为DCL双重检查锁.

他是通过首先的第一次检查单例是否被初始化,然后进入锁的代码块,后再检查一次是否已经初始化单例,这样可以有效的避免在进过第一次的检查时,检查结果为true,但是实际上另一个线程已经准备初始化该单例了.然后导致初始化多个单例.

但是为什么需要volatile关键字呢?

首先我们要了解对象的创建过程(new关键字),它简单的分为三个阶段:

1.分配对象内存空间.

2.初始化对象.

3.设置对象指向内存空间.

那么实际上第三步和第二部的关系是可以进行互换的,在JVM的优化中存在一种指令重排序的现象,为了加快JVM的运行速度,

指令重排序会在不影响结果的情况下,对JVM的指令进行重新排序.

那么当出现指令重排序时,原本1,2,3的顺序则可能变为1,3,2.此时当代码运行到3时,另一个线程恰好在获取该单例,那么此时代码就会返回一个没有初始化完成的单例对象,这是非常危险的. (如下图所示)

现在说会volatile关键,这个关键字有两个作用

1.保证对象的可见性.

2.防止指令重排序.

今天来说的是它的第二个作用,当使用了volatile修饰这个单例时,JVM就能确保new一个对象的过程是1,2,3的顺序,自然就不会发布一个没有被初始化完成的对象了.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值