单例模式为什么要加volatile修饰?

单例模式为什么要加volatile来修饰?
解析:
这里我们自己应该要先搞清楚面试官问的到底是什么?因为单例模式有四种实现:饿汉模式,懒汉模式,静态内部类,枚举 搞清楚问的是哪一种,其实只要自己都会写的话 就很清楚的
知道这里问的是懒汉模式的变量为什么要用volatile来修饰?
搞清楚了问的是什么,接下来就要明白懒汉模式的具体实现到底是什么样的?

懒汉模式的实现代码(Coding):

/**
 * 懒汉模式:指的不是类加载就开始创建,它是延迟加载的,指正在调用使用单例实例的时候才开始创建
 */
public class SingleTonDemo02 {
    // 1、私有化构造器
    private SingleTonDemo02(){}
    // 2、定义静态变量 懒汉模式的这个变量需要用volatile来修饰(原因的话后面再说)
    private static volatile SingleTonDemo02 singleTonDemo02 = null;
    // 3、公开获取INSTANCE(单例实例)的方法
    public static SingleTonDemo02 getInstance() {
        // 先创建 要考虑高并发的情况 因此采用双重校验锁和volatile来保证线程安全
        if (singleTonDemo02 == null) { // 第一次校验
            // 上锁
            synchronized (SingleTonDemo02.class) {
                if (singleTonDemo02 == null) { // 第二次校验
                    // 才开始创建
                    singleTonDemo02 = new SingleTonDemo02();
                }
            }
        }
        return singleTonDemo02;
    }
}

我们会发现懒汉模式 它实现的时候 本身就用两次的if和synchronized来保证线程安全性 那为什么还要给变量加上volatile来修饰?

搞清楚问题前 我们应该先知道volatile到底有什么作用!简单来说:volatile有两个作用:1、解决内存可见性问题 2、防止指令重排

具体来说:

在并发环境下 有三大特性:原子性、有序性、可见性。而内存可见性问题 就是指多个线程操作同一个变量 如果某个线程修改了该变量 那其他线程是感应不到的,这就是内存可见性问题

,那如何解决呢:使用volatile! 具体来说 就是使用了volatile 就会将CPU的高级缓存给写入主内存中 读取的时候也是从主内存中来读取的,这样一来就能保证内存的可见性。底层是基于系统

的内存屏障实现的,因为使用了内存屏障,所以就会禁止指令重排,保证了有序性。

总结:

使用volatile可以解决内存可见性问题和防止指令重排,而单例模式使用volatile主要是用volatile后一个特性(防止指令重排),从而避免在多线程使用的情况下,由于某个线程读取到一个未完全

实例化的对象,而导致程序出错!

posted @ 2023-02-04 10:39  AxeBurner  阅读(44)  评论(0编辑  收藏  举报