最稳妥的Java单例线程安全方案是利用JVM类加载或枚举语义:饿汉式靠类加载阶段初始化、静态内部类(Holder)靠内部类延迟加载、枚举则天然防反射与序列化破坏,三者均无需手动同步且绝对线程安全。

要让单例模式在 Java 多线程环境下真正线程安全,关键不是“加锁就行”,而是选对机制、避开竞态条件和内存可见性陷阱。最稳妥的方式是利用 JVM 本身提供的类加载或枚举语义,而不是靠手动同步。
饿汉式:类加载即初始化,天然线程安全
静态 final 字段在类首次主动使用(如调用 getInstance)前,由 JVM 在类加载阶段完成初始化。这个过程由 ClassLoader 串行执行,无需任何同步关键字,绝对线程安全。
- 适合构造轻量、启动必用的对象(如日志门面、基础配置管理器)
- 缺点是不懒加载——哪怕从不调用 getInstance,实例也会在类加载时创建
- 可在构造函数中加入反射防护,防止 newInstance 绕过私有构造
静态内部类(Holder 模式):懒加载 + 类加载安全
把单例实例放在一个私有静态内部类的 static final 字段里。外部类加载时,内部类不会被加载;只有第一次调用 getInstance 触发 SingletonHolder.INSTANCE 时,JVM 才加载并初始化该内部类——而这一过程仍由类加载机制保证唯一性和线程安全。
- 无 synchronized 开销,无 volatile 修饰负担,性能接近字段直取
- 真正按需初始化,避免饿汉式的资源闲置
- 构造函数保持私有,且内部类无法被外部反射直接访问,安全性高
枚举单例:防反射、防序列化、线程安全三位一体
Java 枚举类型由 JVM 保障每个常量仅初始化一次,且枚举实例在类加载时预创建,反序列化时也强制复用已有实例,天然规避了反射攻击和序列化破坏问题。
立即学习“Java免费学习笔记(深入)”;
- 写法极简:public enum Singleton { INSTANCE; }
- 调用直接用 Singleton.INSTANCE.doSomething()
- 唯一缺点:无法延迟到首次使用再初始化,且不能继承、不能实现延迟初始化逻辑
双重检查锁定(DCL):可用但需严格满足条件
若必须懒加载且不能用枚举或 Holder,DCL 是可行方案,但必须同时满足三项:
- instance 字段必须用 volatile 修饰(禁止指令重排序,确保可见性)
- 构造函数内增加非空检查(防止反射绕过私有构造)
- 两次判空 + synchronized 块缺一不可
漏掉 volatile 或任意一次判空,都可能返回未完全初始化的对象,引发 NPE 或状态不一致。


















