没有理想的人不伤心

设计模式 - 单例模式

2025/08/22
1
0

image.png

一、什么是单例模式?

单例模式(Singleton Pattern)是一种创建型设计模式,其核心目标是确保一个类在整个应用程序中只能创建一个实例,并提供一个全局唯一的访问点供外部获取该实例。

二、为什么要使用单例模式?

单例模式的核心价值在于控制实例数量,适用于以下场景:

  1. 节省资源:某些对象的创建成本高(如数据库连接池、线程池、配置管理器),重复创建会浪费内存、CPU 等资源。单例模式通过唯一实例避免资源浪费。
  2. 保证数据一致性:当多个地方需要操作同一个共享资源(如全局配置、计数器)时,单例模式能确保所有操作针对同一个实例,避免数据不一致。
  3. 控制访问权限:通过单例的全局访问点,可统一管理对资源的访问(如限制并发访问次数)。

三、Java 实现单例模式的示例(双重检查锁方式)

单例模式有多种实现方式,其中双重检查锁(Double-Checked Locking) 是最常用的线程安全且懒加载(按需创建实例)的方式,适合高并发场景。

public class Singleton {
    // 1. 私有静态变量,存储唯一实例(volatile 保证多线程下的可见性和禁止指令重排序)
    private static volatile Singleton instance;

    // 2. 私有构造方法,禁止外部通过 new 创建实例
    private Singleton() {
        // 防止通过反射强制创建实例(可选增强)
        if(instance!= null) {
            throw new RuntimeException("单例模式禁止反射创建实例");
        }
    }

    // 3. 公有静态方法,提供全局访问点
    public static Singleton getInstance() {
        // 第一次检查:如果实例已存在,直接返回(避免每次加锁的性能消耗)
        if(instance == null) {
            // 加锁:确保多线程下只有一个线程进入创建逻辑
            synchronized(Singleton.class) {
                // 第二次检查:防止多个线程等待锁后重复创建实例
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

单例模式的关键:

  • 类中定义私有静态变量存储唯一实例
  • 私有构造方法
  • 公有 get 方法获取唯一实例

代码关键说明:

  1. 私有构造方法 private Singleton() 确保外部无法通过 new Singleton() 创建实例,从根源上控制实例数量。
  2. volatile 关键字:修饰 instance 变量,防止多线程环境下因“指令重排序”导致的“半初始化实例”问题(即一个线程拿到未完全初始化的实例)。
  3. 双重检查
    • 第一次检查( if(instance == null)):避免每次调用 getInstance() 都加锁,提高性能。
    • 第二次检查(同步块内):防止多个线程同时通过第一次检查后,等待锁释放时重复创建实例。
  4. 反射防护(可选):构造方法中判断 instance!= null 时抛异常,防止通过反射强制调用私有构造方法创建新实例。

其他常见实现方式:

  • 饿汉式:类加载时直接创建实例( private static final Singleton instance = new Singleton();),线程安全但可能提前占用资源。
  • 静态内部类:通过静态内部类的延迟加载特性实现懒加载(推荐,线程安全且简洁)。
  • 枚举:天然防止反射和序列化破坏单例(《Effective Java》推荐,简洁但灵活性较低)。

实际开发中,双重检查锁和静态内部类是最常用的两种方式,需根据是否需要懒加载、是否在意反射防护等需求选择。