在Java 5及以上版本中,可以通过将单例的实例声明为volatile来修复双重检查锁定(如果你的代码运行在此之前的版本,请注意这种修复方法并不适用)。下面是一个使用volatile关键字的Double Checked Locking单例模式的示例:
public class Singleton {// 使用volatile关键字修饰单例实例private static volatile Singleton instance;private Singleton() {// 构造函数私有化}public static Singleton getInstance() {if (instance == null) { // 第一次检查synchronized (Singleton.class) { // 同步块if (instance == null) { // 第二次检查instance = new Singleton(); // 注意,此时volatile禁止指令重排序}}}return instance;}}
在上述代码中,instance变量被声明为volatile,确保了以下两点:
-
可见性:当instance变量被初始化成Singleton实例时,多个线程正确地处理instance变量的状态。
-
防止指令重排序:在没有volatile修饰符的情况下,编译器可能会重新排序指令,并且其他线程可能看到一个还没有完全构建的实例(即半初始化的实例),可能会导致程序出现错误的行为。
注意:instance = new Singleton()这条语句实际上可以分解为以下几个指令:
-
分配内存:为 Singleton 对象分配内存空间。
-
初始化对象:调用 Singleton 的构造函数,初始化对象。
-
将引用指向分配的内存:将 instance 引用指向新创建的 Singleton 对象。
结论
通过在声明字段时使用volatile关键字,可以解决Double Checked Locking问题,确保在多线程环境中共享变量的状态对于所有线程都是一致的。然而,即使使用了volatile,Double Checked Locking依然是一个容易出错的模式,因此通常建议使用其他更简单、更清晰的方式来实现线程安全的单例,例如使用枚举类型或者内部静态类来实现单例模式。
本篇文章来源于微信公众号: 互联网面试小帮手
微信扫描下方的二维码阅读本文

Comments NOTHING