java标准单例有四种可靠实现:1.饿汉式(类加载即初始化,线程安全但不懒加载);2.静态内部类(懒加载+线程安全,推荐日常使用);3.枚举(防反射/反序列化,安全性最强);4.双重检查锁(需volatile+synchronized+两次判空,慎用)。

直接用Java基础类库就能写出标准、可靠、线程安全的单例,关键不是“造轮子”,而是选对机制、避开陷阱。JVM本身提供的类加载、静态初始化、枚举语义,就是最坚实的基础——不需要额外依赖第三方库。
饿汉式:用类加载机制保线程安全
这是最朴素也最稳妥的方式。JVM保证类的静态字段只在首次主动使用时初始化一次,且整个过程天然串行、不可打断。
- 实例在类加载阶段就创建,绝对线程安全,无需任何同步关键字
- 适合轻量对象或启动必用的核心组件(如配置管理器、日志门面)
- 注意:如果构造耗时或占用大量资源,又可能长期不用,会带来启动延迟或内存浪费
示例写法:
public class ConfigManager {
private static final ConfigManager INSTANCE = new ConfigManager();
private final Properties configs;
private ConfigManager() {
configs = new Properties();
try {
configs.load(getClass().getResourceAsStream("/app.properties"));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static ConfigManager getInstance() {
return INSTANCE;
}
}
静态内部类:懒加载 + 类加载安全
它把“延迟创建”和“线程安全”完美结合,是日常开发中最推荐的方案之一。外部类不加载,内部类就不会触发初始化;而内部类的静态字段初始化,仍由JVM类加载机制保障唯一性。
- 无synchronized开销,无volatile修饰负担,性能接近直接访问字段
- 真正按需加载,避免饿汉式的资源闲置问题
- 构造函数保持私有,不暴露任何可被反射绕过的漏洞
示例写法:
public class CacheService {
private CacheService() {}
private static class Holder {
static final CacheService INSTANCE = new CacheService();
}
public static CacheService getInstance() {
return Holder.INSTANCE;
}
}
枚举单例:防反射、防反序列化、一行解决
这是JVM层面最强的安全保障。枚举类型由语言规范强制约束:不能被反射实例化(Enum构造器受保护),反序列化时也直接返回已有实例,不会新建。
- 语法极简,语义明确,天然支持序列化场景(如RPC、缓存持久化)
- 适用于高安全性要求的场景,比如密钥管理器、全局计数器、权限中心
- 若需携带状态或复杂初始化逻辑,可在枚举常量后加构造块或方法
示例写法:
public enum GlobalCounter {
INSTANCE;
private final AtomicInteger count = new AtomicInteger(0);
GlobalCounter() {
// 可在此做轻量初始化
}
public int increment() {
return count.incrementAndGet();
}
}
双重检查锁(DCL):慎用但需懂原理
它试图兼顾懒加载与性能,但必须严格满足三个条件才真正安全:synchronized块、两次判空、volatile修饰字段。缺一不可,否则可能因指令重排序导致其他线程拿到未完全构造的对象。
- 仅建议在需要兼容老JDK(如Java 5以下)或已有代码强耦合该模式时采用
- volatile不只是防止可见性问题,更是禁止new操作的指令重排(如分配内存→初始化→赋值,重排后可能变成分配内存→赋值→初始化)
- 构造函数内不应调用可被重写的非final方法,避免this逃逸
正确写法示例:
public class DatabaseConnectionPool {
private static volatile DatabaseConnectionPool instance;
private DatabaseConnectionPool() {
// 初始化连接池...
}
public static DatabaseConnectionPool getInstance() {
if (instance == null) {
synchronized (DatabaseConnectionPool.class) {
if (instance == null) {
instance = new DatabaseConnectionPool();
}
}
}
return instance;
}
}
不复杂但容易忽略
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











