在单例模式中,为了保证效率的同时,保证线程安全,我们会了解这一段代码
双重校验锁
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步骤开辟了空间并将该空间分配给该对象
- dup初步初始化了对象(赋值为0)
- invokespecial为用户定义的构造方法
- putstatic 为赋值给引用
依据happens before原则,第1、2步的顺序计算机将不会改变(有了空间才能操作)
但是第3、4步却是可以重排序的
说人话就是在构造方法执行前,引用就拿到了对象值
为了防止对象没有初始化
我们引入volatile,禁止3、4步骤重排序,保证线程安全