这里有两种实现方式,双重检查锁定(DCL)静态内部类

DCL

public class Singleton {
// volatile保证可见性和禁止指令重排序
private static volatile Singleton instance;

// 私有构造方法
private Singleton() {
// 防止反射攻击
if (instance != null) {
throw new RuntimeException("Use getInstance() method to get the single instance");
}
}

public static Singleton getInstance() {
// 第一次检查,避免不必要的同步
if (instance == null) {
synchronized (Singleton.class) {
// 第二次检查,确保只有一个实例被创建
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}

当第一次检查发现实例为null时,进入同步块,确保只有一个线程能进入创建实例的代码

静态内部类

public class Singleton {
// 私有构造方法
private Singleton() {
// 防止反射攻击
if (SingletonHolder.INSTANCE != null) {
throw new RuntimeException("Use getInstance() method to get the single instance");
}
}

// 静态内部类
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}

JVM在类加载阶段会加锁,保证一个类只被加载一次,静态内部类SingletonHolder只有在被主动使用时才会加载,由JVM保证INSTANCE只被初始化一次

外部类加载时不会立即加载内部类,只有当调用getInstance()时才会触发SingletonHolder的加载