上一篇                     
               
			  Java单例模式如何正确实现?
- 后端开发
- 2025-07-07
- 2278
 单例模式确保类仅有一个实例,并提供全局访问点,常用实现有饿汉式(线程安全但立即加载)、懒汉式(延迟加载需同步锁)、静态内部类(延迟且线程安全)及枚举(最简洁,防反射序列化破坏)。
 
饿汉式(线程安全)
public class Singleton {
    // 类加载时直接初始化
    private static final Singleton INSTANCE = new Singleton();
    // 私有构造方法防止外部实例化
    private Singleton() {}
    public static Singleton getInstance() {
        return INSTANCE;
    }
} 
- 优点:线程安全(JVM类加载机制保证)
- 缺点:类加载时即创建实例,可能造成资源浪费
- 适用场景:实例占用资源少且频繁使用
懒汉式(线程不安全版)
public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {  // 线程不安全点
            instance = new Singleton();
        }
        return instance;
    }
} 
- 风险:多线程下可能创建多个实例
- 仅限单线程环境使用
双重检查锁(DCL,线程安全)
public class Singleton {
    private static volatile Singleton instance; // volatile禁止指令重排序
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {                  // 第一次检查
            synchronized (Singleton.class) {     // 加锁
                if (instance == null) {          // 第二次检查
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
} 
- 关键点:volatile防止JVM指令重排序(避免返回未初始化的对象)
- 优点:线程安全且延迟加载
- 工业级推荐方案
静态内部类(线程安全)
public class Singleton {
    private Singleton() {}
    private static class Holder {
        static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;  // 首次调用时加载内部类
    }
} 
- 原理:利用JVM类加载机制(静态内部类在调用时才加载)
- 优点:无需同步锁,兼顾线程安全和懒加载
枚举(最佳实践)
public enum Singleton {
    INSTANCE;  // 枚举实例天然单例
    public void doSomething() {
        // 业务方法
    }
}
// 调用方式:Singleton.INSTANCE.doSomething(); 
- 优势: 
  - 绝对线程安全(JVM保证)
- 防止反射攻击和序列化破坏单例
 
- 《Effective Java》作者Joshua Bloch推荐方案
破坏单例的场景及防护
| 威胁 | 防护方案 | 
|---|---|
| 反射攻击 | 私有构造器中添加 throw new RuntimeException() | 
| 序列化破坏 | 实现 readResolve()方法返回实例 | 
// 序列化防护示例
protected Object readResolve() {
    return getInstance();
} 
总结与选择建议
- 简单场景:直接使用饿汉式
- 延迟加载需求:优先选择静态内部类或枚举
- 高并发系统:双重检查锁(DCL)
- 终极方案:枚举(防反射/序列化攻击)
单例模式虽实用,但需注意两点:
- 过度使用会导致代码耦合度高(违背单一职责原则)
- 在分布式系统或类加载器不同的环境中可能失效
引用说明:
双重检查锁实现参考《Java并发编程实战》(Brian Goetz等);枚举方案出自《Effective Java》(Joshua Bloch);类加载机制依据JVM规范(Oracle官方文档)。

 
 
 
			 
			 
			 
			 
			 
			