JVM深入学习-1.4 详解DCL的单例模式为什么需要加volitle?通过class加载流程中的Link阶段和初始化阶段理解为什么要加volitle

先展示一段 double check lock思想的单例模式代码:

public class SingletonLh4 {
	private static volatile SingletonLh4 singleton;
	private String instanceName;

	private SingletonLh4() {
		this.instanceName = "SingletonLh4";
	}

	public static SingletonLh4 getInstance() {
		if (singleton == null) {
			synchronized (SingletonLh4.class) {
				if (singleton == null) {
					singleton = new SingletonLh4();
				}
			}
		}
		return singleton;
	}
}

如果在不考虑 volatile 关键字的情况下,如下图所示:

public class SingletonLh4 {
	private static SingletonLh4 singleton; // 1
	private String instanceName;

	private SingletonLh4() {
		this.instanceName = "SingletonLh4";
	}

	public static SingletonLh4 getInstance() {
		if (singleton == null) {
			synchronized (SingletonLh4.class) {
				if (singleton == null) {
					singleton = new SingletonLh4();
				}
			}
		}
		return singleton;
	}
}

     如上图,按照代码逻辑分析后,大多数人确定这样应该也能100%保证单例实例的创建,感觉没啥问题。但是如果大家能考虑到cpu执行指令的时候允许乱序的,那么就需要重新分析上图代码了。

     如果上述代码 1 处 SingletonLh4 singleton 没有volatile关键字的修饰,多个线程同时调用 getInstance() 的时候,只有一个线程能获取锁,并给 singleton 创建一个 SingletonLh4 实例,但是这个 new SingletonLh4()  是一个多指令操作,实例化的过程包括: instanceName 的实例化和 singleton 的实例化。根据 jvm 运行时指令重排序和 Happens-Before 规则,singleton 实例化和instanceName 实例化并没有先后顺序的约束,所以有可能出现 instanceName 先实例化,然后再实例化 singleton 。这个时候恰好有另一个线程调用 getInstance() 方法,发现 singleton 不为空,这个时候就直接返回 singleton 实例,其实这个实例不是一个完整的实例,因为 instanceName 是为空的。

   如果使用了volatile关键字的修饰,那么 new SingletonLh4() 中的 singleton 实例化和instanceName 实例化会受到 Happens-Before 原则的约束,实例化时不会发生乱序,所以会先实例化 instanceName,再实例化 singleton 。所以不会出现返回的 singleton 实例不完整的现象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

荆茗Scaler

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值