美文网首页设计模式
单例模式的双检锁为什么要加volatile?

单例模式的双检锁为什么要加volatile?

作者: 饱饱想要的灵感 | 来源:发表于2024-09-19 09:43 被阅读0次

关于单例模式可查看博客 java 单例模式的5种实现方式

我们直接上代码, 看看不加volatile会出什么问题?

public class Friday{
    private static Friday friday;
    
    private Friday() {}
 
    public static Friday getInstance() {
        if (friday == null) {
            synchronized(Friday.class) {
                if(friday == null) {
                    friday = new Friday(); //这行代码是问题根源所在
                }
            }
        }
        return friday;
    }
 
}

为什么那行代码有问题呢?

因为friday = new Friday();这段代码并非原子操作,可以分为3步骤,伪代码如下:

memory = allocate();//1:分配对象的内存空间

initInstance(memory)//2:在内存空间内初始化对象

instance = memory;//3:将instance指向刚分配的内存空间

其中第2步与第3步之间可能会发生指令重排序:也就是变成

memory = allocate();//1:分配对象的内存空间

instance = memory;//3:将instance指向刚分配的内存空间(此时还没有初始化对象)

initInstance(memory)//2:在内存空间内初始化对象

重排序之后,在单线程中并不会影响语义,但是多线程就不一定了。

时间段 线程A 线程B
t0 A1:memory = allocate();//1分配对象的内存空间
t1 A3:instance = memory;//3:将instance指向刚分配的内存空间(此时还没有初始化对象)
t2 B1:判断instance是否为空
t3 B2:由于instance不为null,线程B将返回instance引用的对象(而这个时候对象还没有初始化)
t4 A2:initInstance(memory)//在内存空间内初始化对象
t5 A4:返回instance引用的对象

可以看出, 线程B拿到的instance可能还未初始化成功,如果拿去操作,就出问题了。

解决方法是在变量声明时加上volatile修饰符, 如:private static volatile Friday friday;

这是因为jdk1.5对volatile进行优化, 有一个作用是禁止指令重排序。

相关文章

网友评论

    本文标题:单例模式的双检锁为什么要加volatile?

    本文链接:https://www.haomeiwen.com/subject/wosoljtx.html