第 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() 方法,否则反序列化会创建新实例;
  • 反射攻击:私有构造函数可通过反射被调用,需在构造函数中添加判断(若实例已存在则抛异常)。
相关推荐
yeccheng42 分钟前
MySQL 索引超详解:从底层 B+ 树到面试高频考点
java·开发语言·jvm·mysql·面试
这个昵称不容易1 小时前
SpringBoot 读书笔记共享平台部署实战:97 个 Java 文件 / 113 个接口 / 10 张表
java·springboot·毕设
金銀銅鐵3 小时前
一个 Java 文件实现《孫子兵法·始計篇》中英对照阅读器
java·后端·ai编程
DevOpenClub3 小时前
高考教育信息问答 API:会话参数、资料引用与流式响应
java·数据库·高考
bro_Java6664 小时前
《排序的底层逻辑:比较、交换与分治》
java·算法·排序算法
文丑颜不良啊5 小时前
LeetCode2081~2100题目解析
java·leetcode
玖米GEO运营王总监5 小时前
2026年账号矩阵协同效应怎么量化:三个指标与公式结构
java·大数据·数据库
是2的10次方啊6 小时前
设计模式与生活⑭:一栋楼,共用一份热
设计模式
叼烟扛炮7 小时前
[LangChain] 学习笔记(03):打破失忆症——对话机制与上下文管理
java·前端·javascript·笔记·学习·langchain
文丑颜不良啊7 小时前
LeetCode2061~2080题目解析
java·leetcode