✨你了解volatile,但你知道它在单例模式中的作用吗?

1,713 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

Code皮皮虾 一个沙雕而又有趣的憨憨少年,和大多数小伙伴们一样喜欢听歌、游戏,当然除此之外还有写作的兴趣,emm...,日子还很长,让我们一起加油努力叭🌈

✨作用

以 双重检查单例模式为例,先上代码

public class Singleton {

    public Singleton() {
    }

    private static volatile Singleton singleton;

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

}

如上述代码所示,singleton 用了 volatile 修饰,而我们都知道 volatile 的作用

  1. 不能保证原子性
  2. 保证共享变量的可见性
  3. 禁止指令重排序

那么在单例模式中,volatile的作用到底是什么呢?

其实,在单例模式中,volatile的作用主要是 禁止指令重排序

那么为什么呢?

在上述代码中,singleton = new Singleton(); 可分解为以下步骤:

  1. 分配对象内存空间
  2. 初始化对象
  3. 设置 singleton 指向分配的内存地址

但是步骤2,3是可能交换的,也就是发生重排序,但是根据 Java语言规范 intra-thread semantics,它是允许那些在单线程内,不会改变单线程程序执行结果的重排序,也就是说,虽然步骤2,3发生重排序,但是对于单线程来说,初次访问对象时,其结果都是正确的,所以即使重排序也无所谓了。



但是在多线程环境中,这就会出现问题,例如,如下多线程发生重排序案例:

时间线程A线程B
t1分配对象空间
t2设置 singleton 指向分配的内存空间
t3判断 singleton 是否为空
t4由于 singleton 不为null,线程B将访问singleton 引用的对象
t5初始化对象
t6访问 singleton 引用的对象

有上述表格流程可以看出,在发生重排序的情况下,会导致线程B在 t3 时间下,判断出 singleton 不为null,那么线程B就会拿到这个 singleton 去做别的事,那么此时这个 singleton 没有初始化,那么就会报错,这就出了问题。

正常流程而言,在t2时间线程A应该对 singleton初始化,那么线程B在


可能会有小伙伴就差临门一脚的感觉就懂了,那我根据代码再说一遍

public class Singleton {

    public Singleton() {
    }

    private static volatile Singleton singleton;

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

}

根据代码而言,如果线程A在 第12行 即 singleton = new Singleton();发生重排序,那么线程B在 第9行即第一个if (singleton == null)处就有可能判断出 singleton不为null,进而拿到返回的 singleton 去做别的事进而导致报错。



讲到这里相信各位小伙伴差不多都懂了,如果还不懂可以多看两遍。

所以为了解决这个问题,就使用 volatile来修饰 singleton,来禁止重排序而可能出现的问题。

😉精选专栏

毛遂自荐,给大家推荐一下自己的专栏😁,欢迎小伙伴们收藏关注😊

小白学Java

MybatisPlus专栏

App爬虫专栏

PC端爬虫专栏

大厂面试题专栏


❤最后

我是 Code皮皮虾,一个热爱分享知识的 皮皮虾爱好者,未来的日子里会不断更新出对大家有益的博文,期待大家的关注!!!

创作不易,如果这篇博文对各位有帮助,希望各位小伙伴可以==一键三连哦!==,感谢支持,我们下次再见~~~


一键三连.png