跳到主要内容

如何使用双重检查锁定在 Java 中创建线程安全的单例?

参考答案:

双重检查锁定 (Double-Checked Locking) 是一种在 Java 中实现线程安全单例模式的常见方法。这种方法结合了延迟初始化和锁机制,可以在多线程环境下安全地创建单例实例。

下面是一个使用双重检查锁定实现单例模式的示例代码:

public class Singleton {
    private static volatile Singleton instance;

    private Singleton() {
        // 私有构造函数,防止外部通过 new Singleton() 创建实例
    }

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

这里的关键点有:

  1. private static volatile Singleton instance;:使用 volatile 关键字确保 instance 变量的可见性。在多线程环境下,当一个线程修改了一个共享变量的值,其他线程能够立即看到修改后的值。volatile 可以防止 JVM 对指令进行重排序,从而确保在多线程环境下创建单例实例的正确性。
  2. private Singleton():将构造函数设置为私有,防止外部通过 new Singleton() 创建实例。
  3. public static Singleton getInstance():提供一个静态方法用于获取单例实例。在方法中,首先检查 instance 是否为 null,如果是,则进入同步块。在同步块内,再次检查 instance 是否为 null,如果是,则创建一个新的 Singleton 实例并赋值给 instance。这样做的好处是,当 instance 已经被初始化后,后续的线程无需再进入同步块,从而提高了性能。

需要注意的是,双重检查锁定虽然可以提高性能,但在 Java 1.5 之前的版本中,由于 JVM 对 volatile 的实现可能存在问题,双重检查锁定可能无法正常工作。因此,在 Java 1.5 及以后的版本中,双重检查锁定是安全的。如果你使用的是 Java 1.5 之前的版本,建议使用其他方式实现线程安全的单例模式,如饿汉式或懒汉式加锁。