第 1 天:单例模式(Singleton Pattern)—— 创建型模式

第 1 天:单例模式(Singleton Pattern)------ 创建型模式

1. 核心定义

单例模式确保一个类仅有一个实例 ,并提供一个全局访问点来获取该实例。它的核心是 "控制实例数量",避免重复创建消耗资源的对象(如数据库连接池、配置管理器)。

2. 解决的核心问题

  • 避免多个实例导致的资源浪费(如频繁创建数据库连接);
  • 防止多个实例引发的数据不一致(如配置文件读取实例,多实例可能导致配置冲突);
  • 提供统一的全局访问入口,简化对象调用。

3. 关键设计要点

  • 私有构造函数 :禁止外部通过 new 关键字创建实例;
  • 私有静态成员变量:存储类的唯一实例;
  • 公有静态方法:作为全局访问点,返回唯一实例(需处理线程安全问题)。

4. 常见实现方式(Java 示例)

方式 1:饿汉式(线程安全,简单但可能浪费资源)

"饿汉式" 在类加载时就创建实例,避免线程安全问题,但如果实例未被使用,会提前占用内存。

csharp 复制代码
public class HungrySingleton {
    // 1. 私有静态成员变量:类加载时创建唯一实例
    private static final HungrySingleton INSTANCE = new HungrySingleton();
    
    // 2. 私有构造函数:禁止外部new
    private HungrySingleton() {}
    
    // 3. 公有静态方法:返回实例
    public static HungrySingleton getInstance() {
        return INSTANCE;
    }
}

方式 2:懒汉式(线程不安全→线程安全优化)

"懒汉式" 在首次调用 getInstance() 时才创建实例,节省内存,但需额外处理线程安全(否则多线程下可能创建多个实例)。

线程安全优化版(双重检查锁定)

csharp 复制代码
public class LazySingleton {
    // 1. 私有静态成员变量:volatile防止指令重排序(关键!)
    private static volatile LazySingleton INSTANCE;
    
    // 2. 私有构造函数
    private LazySingleton() {}
    
    // 3. 公有静态方法:双重检查锁定
    public static LazySingleton getInstance() {
        // 第一次检查:避免已创建实例时的锁竞争
        if (INSTANCE == null) {
            synchronized (LazySingleton.class) {
                // 第二次检查:防止多线程同时进入第一个检查后重复创建
                if (INSTANCE == null) {
                    INSTANCE = new LazySingleton();
                }
            }
        }
        return INSTANCE;
    }
}

方式 3:静态内部类(推荐,线程安全且延迟加载)

利用 Java "静态内部类加载时机" 的特性:内部类在被调用时才加载,既实现延迟加载,又天然避免线程安全问题(类加载过程由 JVM 保证线程安全)。

csharp 复制代码
public class StaticInnerClassSingleton {
    // 1. 私有构造函数
    private StaticInnerClassSingleton() {}
    
    // 2. 静态内部类:存储唯一实例
    private static class SingletonHolder {
        private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }
    
    // 3. 公有静态方法:调用内部类的实例
    public static StaticInnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

5. 应用场景

  • 系统中只能有一个实例的对象,如:

    • 数据库连接池(DataSource);
    • 配置文件管理器(读取全局配置);
    • 日志工具类(避免多实例写入日志时的冲突);
    • 操作系统的任务管理器、回收站。

6. 注意事项

  • 线程安全:懒汉式必须处理线程安全,否则多线程环境下会破坏 "单例" 特性;
  • 序列化问题 :若单例类实现 Serializable,需重写 readResolve() 方法,否则反序列化会创建新实例;
  • 反射攻击:私有构造函数可通过反射被调用,需在构造函数中添加判断(若实例已存在则抛异常)。
相关推荐
mit6.82417 分钟前
[C# starter-kit] 命令/查询职责分离CQRS | MediatR |
java·数据库·c#
诸神缄默不语41 分钟前
Maven用户设置文件(settings.xml)配置指南
xml·java·maven
任子菲阳44 分钟前
学Java第三十四天-----抽象类和抽象方法
java·开发语言
学Linux的语莫1 小时前
机器学习数据处理
java·算法·机器学习
找不到、了1 小时前
JVM的即时编译JIT的介绍
java·jvm
rongqing20191 小时前
Google 智能体设计模式:人机协同(HITL)
设计模式
西瓜er2 小时前
JAVA:Spring Boot 集成 FFmpeg 实现多媒体处理
java·spring boot·ffmpeg
你总是一副不开心的样子(´ . .̫ .2 小时前
一、十天速通Java面试(第三天)
java·面试·职场和发展·java面试
迎風吹頭髮2 小时前
UNIX下C语言编程与实践63-UNIX 并发 Socket 编程:非阻塞套接字与轮询模型
java·c语言·unix
我是华为OD~HR~栗栗呀2 小时前
23届考研-Java面经(华为OD)
java·c++·python·华为od·华为·面试