Prompts-MCP 686 skills · ai / design / design-pattern / framework / fundamentals / habit / lang / tech-selection /mcp/sse
design-pattern design-pattern/singleton/thread-safe-singleton.md medium

singleton-thread-safe

线程安全单例的三种 Java 实现与取舍 — 枚举(首选)/ 静态内部类(懒加载)/ 双重检查锁(volatile 不可省)。Use when 写全局唯一实例 / 选单例实现 / 评审双重检查锁是否漏 volatile 时。

单例线程安全单例双重检查锁静态内部类枚举单例volatiledcl
paths
  • *.java

Singleton · 线程安全单例

Spring 管理的 Bean 默认就是容器级单例,业务里优先交给 Spring;本条针对不走容器的纯 Java 单例。

规则

实现 线程安全 懒加载 防反射/序列化破坏 选用
枚举 ✅(JVM 保证) ❌ 类加载即建 ✅ 天然防御 首选
静态内部类 ✅(类加载机制) ✅ 用到才加载 需懒加载时
双重检查锁 DCL ✅(须 volatile 一般不必,懂原理即可
饿汉式 创建廉价且必用时

正例:枚举(首选)

public enum Config {
    INSTANCE;
    private final Properties props = load();
    public String get(String key) { return props.getProperty(key); }
}
// 用:Config.INSTANCE.get("k")。天然防反射、防序列化生成第二个实例

正例:静态内部类(懒加载)

public class Resource {
    private Resource() {}
    private static class Holder {            // 外类加载时不初始化
        static final Resource INSTANCE = new Resource();
    }
    public static Resource getInstance() {   // 首次调用才触发 Holder 加载
        return Holder.INSTANCE;
    }
}

双重检查锁:volatile 不可省

public class Conn {
    private static volatile Conn instance;   // ❗ volatile 防指令重排
    private Conn() {}
    public static Conn getInstance() {
        if (instance == null) {              // 第一次检查(免锁)
            synchronized (Conn.class) {
                if (instance == null) {      // 第二次检查(持锁)
                    instance = new Conn();
                }
            }
        }
        return instance;
    }
}

volatilenew 非原子(分配/构造/赋引用三步可重排),别的线程可能读到「已赋引用但未构造完」的半成品对象。

自检

  • [ ] 无特殊需求优先枚举;要懒加载用静态内部类?
  • [ ] 用了双重检查锁,字段是否 volatile?两次 null 检查都在?
  • [ ] 构造器私有,没有别的入口能再造实例?
  • [ ] 在 Spring 项目里,该交给容器单例的没有自己手写?

相关