23种设计模式之【单例模式模式】-核心原理与 Java实践
文章目录
- 单例模式(Singleton Pattern)
- 核心原理
- Java 实践示例
- 单例模式的关键问题
- 单例模式的应用场景
单例模式(Singleton Pattern)
单例模式是 23 种设计模式中的一种创建型模式,其核心思想是确保一个类在整个应用中只有一个实例,并提供一个全局访问点。这种模式常用于管理共享资源(如配置信息、线程池、日志对象等),避免资源竞争或重复创建带来的性能问题。
核心原理
- 私有构造函数:
阻止外部通过new关键字创建实例,确保只能通过类自身提供的方法获取实例 - 静态私有实例:
在类内部维护唯一的实例对象,通常为静态变量 - 公共静态访问方法:
提供全局访问点,确保返回的是同一个实例
负责实例的创建(延迟初始化或饿汉式初始化)
单例模式的核心是 “唯一性” 与 “全局访问”,通过控制实例创建过程,保证在任何情况下都只有一个实例存在。
Java 实践示例
下面实现几种常见的单例模式变体,各有其适用场景:
package com.example.demo;public class SingletonPattern {public static void main(String[] args) {// 测试枚举单例EnumSingleton.INSTANCE.doSomething();// 测试静态内部类单例StaticInnerClassSingleton instance1 = StaticInnerClassSingleton.getInstance();StaticInnerClassSingleton instance2 = StaticInnerClassSingleton.getInstance();System.out.println("静态内部类单例是否相同:" + (instance1 == instance2));}// 1. 饿汉式单例(线程安全,类加载时初始化)public static class EagerSingleton {// 类加载时就初始化实例private static final EagerSingleton INSTANCE = new EagerSingleton();// 私有构造函数,防止外部实例化private EagerSingleton() {}// 公共访问方法public static EagerSingleton getInstance() {return INSTANCE;}}// 2. 懒汉式单例(基础版,线程不安全)public static class LazySingleton {private static LazySingleton instance;private LazySingleton() {}// 非线程安全,多线程环境下可能创建多个实例public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}}// 3. 线程安全的懒汉式(同步方法,性能较低)public static class ThreadSafeLazySingleton {private static ThreadSafeLazySingleton instance;private ThreadSafeLazySingleton() {}// 同步方法保证线程安全,但每次调用都加锁,性能差public static synchronized ThreadSafeLazySingleton getInstance() {if (instance == null) {instance = new ThreadSafeLazySingleton();}return instance;}}// 4. 双重检查锁定(DCL,线程安全且高性能)public static class DoubleCheckedLockingSingleton {// volatile关键字防止指令重排序private static volatile DoubleCheckedLockingSingleton instance;private DoubleCheckedLockingSingleton() {}// 双重检查:减少同步开销,只在实例未创建时加锁public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) { // 第一次检查,无锁synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) { // 第二次检查,有锁instance = new DoubleCheckedLockingSingleton();}}}return instance;}}// 5. 静态内部类单例(推荐,线程安全且延迟初始化)public static class StaticInnerClassSingleton {// 私有构造函数private StaticInnerClassSingleton() {}// 静态内部类,只有在调用getInstance()时才会加载private static class SingletonHolder {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}// 全局访问点public static StaticInnerClassSingleton getInstance() {return SingletonHolder.INSTANCE;}}// 6. 枚举单例(最佳实践,防止反射和序列化破坏单例)public enum EnumSingleton {INSTANCE; // 枚举实例天生单例// 可以添加其他方法public void doSomething() {System.out.println("枚举单例执行操作");}}
}
单例模式的关键问题
- 线程安全:
多线程环境下需保证实例唯一,最简单的方式是使用枚举或静态内部类
DCL 模式需配合volatile关键字防止指令重排序导致的问题 - 防止反射破坏:
私有构造函数可被反射调用(通过setAccessible(true))
枚举单例天然防止反射破坏,其他实现需在构造函数中添加防重入逻辑 - 防止序列化破坏:
实现Serializable接口的单例,反序列化时可能创建新实例
解决方案:重写readResolve()方法返回原有实例 - 单例与依赖注入:
单例模式可能与依赖注入框架冲突,需谨慎使用
可通过容器管理单例(如 Spring 的@Singleton)
单例模式的应用场景
工具类:如日志工具类Logger,全局只需要一个实例
配置管理:应用配置类Config,集中管理配置信息
线程池:ThreadPool全局唯一,避免资源浪费
数据库连接池:ConnectionPool共享连接资源
缓存:应用级缓存实例CacheManager
GUI 组件:如应用程序的主窗口MainFrame
单例模式是最简单的设计模式之一,但实现时需注意线程安全、反射攻击等问题。在实际开发中,枚举单例和静态内部类单例是推荐的实现方式,既能保证线程安全,又具有良好的性能。