单例模式为什么需要volatile关键字?

在单例模式中,为了保证效率的同时,保证线程安全,我们会了解这一段代码
双重校验锁

public class SingletonLazy {
    
    
    private volatile static SingletonLazy data;
    private SingletonLazy(){
    
    
        System.out.println("初始化");
    }
    public SingletonLazy getData() {
    
    
        if (data == null) {
    
    
            synchronized (SingletonBase.class){
    
    
                data=new SingletonLazy();
            }
        }
        return data;
    }
}

要点:临界区必须为类对象,属性必须使用volatile关键字
敲黑板,这里的属性必须为volatile关键字,否则会产生不安全因素

再次科普一下什么是volatile
volatile是java中的关键字,主要有两个功能,禁止指令重排,保证可见性
禁止指令重排:机器在运行过程中,存在指令重排序(目的是为了提高机器资源利用率),但是指令的重排对编程来说是存在隐患的,Happens Before原则

在对象初始化的过程中,data=new SingletonLazy();这一行将在字节码等级被编译为四句命令

查看生成字节码的办法
javac xxxx.java 进行编译
javap 查看字节码,推荐使用javap -v xxxxx.class

结果如下new字节码

  1. new步骤开辟了空间并将该空间分配给该对象
  2. dup初步初始化了对象(赋值为0)
  3. invokespecial为用户定义的构造方法
  4. putstatic 为赋值给引用

依据happens before原则,第1、2步的顺序计算机将不会改变(有了空间才能操作)
但是第3、4步却是可以重排序的
说人话就是在构造方法执行前,引用就拿到了对象值

为了防止对象没有初始化
我们引入volatile,禁止3、4步骤重排序,保证线程安全

猜你喜欢

转载自blog.csdn.net/weixin_44494373/article/details/112061551