DCL(双检锁单例模式)到底需不需要volatile?
程序员文章站
2022-10-04 08:21:13
DCL(双检锁单例模式)到底需不需要volatile?先给答案,确定以及肯定的告诉你,需要使用 volatile。我们先看代码,然后一步一步分析:package cn.frantic.learning.jvm;public class T08_DCL {public volatile static T08_DCL instance;public static T08_DCL getInstance() {if(instance == null) {synch...
先给答案,确定以及肯定的告诉你,需要使用 volatile。我们先给出正确的 DCL 单例模式,然后一步一步分析:
package cn.frantic.learning.jvm;
public class T08_DCL {
public volatile static T08_DCL instance;
public static T08_DCL getInstance() {
if(instance == null) {
synchronized (T08_DCL.class) {
if(instance == null) {
instance = new T08_DCL();
}
}
}
return instance;
}
}
volatile 的作用是什么?
- 保证变量的可见性:当一个线程修改一个被 volatile 修饰的变量的时候,其他的线程可以立刻等到修改后的值。
- 屏蔽指令重排序:指令重排序是编译期和处理器为了高效而对程序的优化手段,他保证(单线程)程序的执行结果不变,但是不保证程序的执行顺序和代码的顺序一致,这里可以参考 CPU 为什么乱序执行(指令重排序)
为什么要用 volatile?
解答之前,我们先看一个简单实例,观察一下 new 一个对象对应的汇编指令,Java 代码如下:
package cn.frantic.learning.jvm;
public class T09_NewObject {
public void test() {
System.out.println("11");
}
public static void main(String[] args) {
T09_NewObject t09_NewObject = new T09_NewObject();
t09_NewObject.test();
}
}
先编译成字节码,javac TT09_NewObject
然后查看汇编命令,javap -c T09_NewObject.class,结果如下:
Compiled from "T09_NewObject.java"
public class cn.frantic.learning.jvm.T09_NewObject {
public cn.frantic.learning.jvm.T09_NewObject();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void test();
Code:
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String 11
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
public static void main(java.lang.String[]);
Code:
0: new #5 // 创建对象,并将对象引用压入栈
3: dup // 栈内复制一份对象的引用并压入栈,此时栈内有两份引用
4: invokespecial #6 // pop 弹出一个引用,并调用对象的构造函数,完成对象的初始化
7: astore_1 // pop 弹出一个引用,并将引用赋值给变量 t09_NewObject
8: aload_1
9: invokevirtual #7 // Method test:()V
12: return
}
从汇编指令中可以看出对象的创建大致分为三部分:
- 创建一个空白对象,也就是分配一块内存
- 调用对象的构造方法完成初始化操作
- 将对象的引用赋值给变量
了解指令重排序的同学,应该就能明白为什么要使用 volatile 了。如果是在单线程的情况下,指令重排序不会印象创建对象最终的结果。但是如果在多线程的情况下,指令重排序很有可能让其他线程拿到的是一个指向空白对象的应用。
本文地址:https://blog.csdn.net/qq_35918357/article/details/107350803
上一篇: Java基础--算法
下一篇: Mybatis-Plus Sql 注入器