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

本文出自——可乐可乐可,作者主页链接:可乐可乐可的个人主页

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码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步骤重排序,保证线程安全

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%