java23种设计模式-单例模式

单例模式(Singleton Pattern)学习笔记

🌟 定义

单例模式 属于创建型设计模式,确保一个类只有一个实例,并提供全局访问点。是Java中最简单但实现最复杂的设计模式。


🎯 适用场景

  1. 需要控制资源访问(如数据库连接池)
  2. 全局配置对象
  3. 日志记录器
  4. 设备管理器(如打印机服务)
  5. 缓存系统
  6. 线程池/连接池管理

🔧 模式结构

📐 类图

Singleton -static instance: Singleton -Singleton() +static getInstance() +otherMethod()


🛠️ 核心组成

  1. 私有静态实例:存储唯一实例
  2. 私有构造方法:防止外部实例化
  3. 静态获取方法:全局访问入口
  4. 线程安全措施:保证多线程环境正确性

📝 代码实现(6种经典写法)

1. 饿汉式(线程安全)

java 复制代码
public class EagerSingleton {
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    
    private EagerSingleton() {
        // 防止反射攻击
        if (INSTANCE != null) {
            throw new IllegalStateException("Already initialized");
        }
    }
    
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

2. 懒汉式(非线程安全)

java 复制代码
public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton() {}
    
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

3. 同步方法懒汉式(线程安全)

java 复制代码
public class SynchronizedSingleton {
    private static SynchronizedSingleton instance;
    
    private SynchronizedSingleton() {}
    
    public static synchronized SynchronizedSingleton getInstance() {
        if (instance == null) {
            instance = new SynchronizedSingleton();
        }
        return instance;
    }
}

4. 双重检查锁(DCL,线程安全)

java 复制代码
public class DCLSingleton {
    private volatile static DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {
        if (instance == null) {
            synchronized (DCLSingleton.class) {
                if (instance == null) {
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}

5. 静态内部类(线程安全)

java 复制代码
public class InnerClassSingleton {
    private InnerClassSingleton() {}
    
    private static class SingletonHolder {
        static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }
    
    public static InnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

6. 枚举式(最佳实践,线程安全)

java 复制代码
public enum EnumSingleton {
    INSTANCE;
    
    public void doSomething() {
        // 业务方法
    }
}

✅ 优点

  1. 严格控实例数量
  2. 全局唯一访问点
  3. 延迟初始化(部分实现)
  4. 减少内存开销(避免重复创建)
  5. 避免资源冲突

⚠️ 缺点

  1. 违反单一职责原则(同时控制创建和业务逻辑)
  2. 单元测试困难(全局状态难以隔离)
  3. 可能隐藏类间耦合关系
  4. 需要特殊处理序列化/反射攻击
  5. 长期持有可能造成内存泄漏

🔒 防御措施

1. 防止反射攻击

java 复制代码
private Singleton() {
    if (instance != null) {
        throw new IllegalStateException("Already initialized");
    }
}

2. 防止序列化破坏

java 复制代码
// 添加readResolve方法
protected Object readResolve() {
    return getInstance();
}

3. 防止克隆破坏

java 复制代码
@Override
protected Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException();
}

🔄 实现对比

实现方式 线程安全 懒加载 防止反射 防止序列化 性能
饿汉式 ⭐⭐⭐⭐
同步方法
双重检查锁 ⭐⭐⭐
静态内部类 ⭐⭐⭐⭐
枚举式 ⭐⭐⭐⭐

💡 实践建议

  1. 优先选择枚举实现(Effective Java推荐)
  2. 需要懒加载时用静态内部类方式
  3. 避免使用synchronized方法(性能差)
  4. 谨慎使用单例模式(考虑依赖注入)
  5. 注意与Spring单例的区别:
    • Spring单例是容器级的
    • 设计模式单例是JVM级的

🚀 典型应用

  1. Runtime类(JDK内置单例)

    java 复制代码
    Runtime runtime = Runtime.getRuntime();
  2. 日志框架(LogManager)

    java 复制代码
    Logger logger = LogManager.getLogManager().getLogger("");
  3. Spring容器(ApplicationContext)

    java 复制代码
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

📌 扩展知识

1. 如何实现线程安全的延迟加载?

使用Initialization-on-demand holder惯用法(静态内部类实现)

2. volatile关键字的作用?

  • 保证可见性
  • 禁止指令重排序
  • 在DCL模式中防止返回未初始化完毕的对象

3. 为什么推荐枚举实现?

  • 自动处理序列化
  • 防止反射攻击
  • 保证线程安全
  • 代码简洁

掌握单例模式的关键在于理解实例控制线程安全的平衡,根据具体场景选择合适的实现方式。在分布式系统、类加载器不同的环境等特殊场景下需要特别注意单例的有效范围。

相关推荐
触底反弹2 小时前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
张小姐的猫19 小时前
【Linux】网络编程 —— HTTP协议(上)
linux·运维·服务器·网络·http·单例模式·策略模式
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范
杨充1 天前
6.设计原则的全景图
设计模式·开源·全栈
杨充1 天前
2.面向对象的特性
设计模式
杨充1 天前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充1 天前
8.反模式与坏味道
设计模式·开源·代码规范
杨充1 天前
3.接口vs抽象类比较
设计模式