【设计模式】【创建型模式】单例模式(Singleton)

简介: 一、入门 什么是单例模式? 单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要全局唯一对象的场景,如配置管理、连接池等。 为什么要单例模式? 节省资源 场景:某些对象创

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD

🔥 2025本人正在沉淀中... 博客更新速度++

👍 欢迎点赞、收藏、关注,跟上我的更新节奏

🎵 当你的天空突然下了大雨,那是我在为你炸乌云

一、入门

什么是单例模式?

单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要全局唯一对象的场景,如配置管理、连接池等。

为什么要单例模式?

  1. 节省资源
    • 场景:某些对象创建和销毁成本高,如数据库连接池、线程池等。
    • 原因:单例模式确保这些资源只创建一次,避免重复创建和销毁,节省系统资源。
  2. 全局访问点
    • 场景:需要在多个模块或组件中共享同一个对象,如配置管理器、日志记录器等。
    • 原因:单例模式提供一个全局访问点,方便不同模块共享同一实例,避免频繁传递对象。
  3. 保持一致性
    • 场景:需要确保某些操作或状态在整个应用中保持一致,如缓存管理、计数器等。
    • 原因:单例模式确保只有一个实例,避免多个实例导致状态不一致。
  4. 控制实例数量
    • 场景:某些情况下,限制实例数量是必要的,如打印机管理、文件系统等。
    • 原因:单例模式确保只有一个实例存在,避免资源冲突或竞争条件。
  5. 简化设计
    • 场景:某些设计模式(如工厂模式、抽象工厂模式)中,单例模式可以简化对象创建和管理。
    • 原因:单例模式减少对象创建的复杂性,使设计更简洁。

      如何实现单例模式?

  6. 私有构造函数:防止外部通过 new 创建实例。
  7. 静态私有实例:类内部持有唯一的实例。
  8. 静态公有方法:提供全局访问点,返回唯一实例。
    饿汉式

    public class Singleton {
         
     // 在类加载时就创建实例
     private static final Singleton INSTANCE = new Singleton();
    
     // 私有构造函数,防止外部通过 new 创建实例
     private Singleton() {
         }
    
     // 提供全局访问点
     public static Singleton getInstance() {
         
         return INSTANCE;
     }
    }
    
  • 实例在类加载时立即创建。
  • 无论是否使用,实例都会提前初始化。

特点

  1. 线程安全:实例在类加载时创建,由 JVM 保证线程安全。
  2. 提前加载:无论是否使用,实例都会在类加载时创建,可能会占用资源。
  3. 实现简单:代码简洁,无需考虑多线程问题。

懒汉式

public class Singleton {
   
    private static Singleton instance;

    private Singleton() {
   }

    public static synchronized Singleton getInstance() {
   
        if (instance == null) {
   
            instance = new Singleton();
        }
        return instance;
    }
}
  • 优点:线程安全。
  • 缺点:每次调用都加锁,性能较差。

双重检查(DCL)

public class Singleton {
   
    private static volatile Singleton instance;

    private Singleton() {
   }

    public static Singleton getInstance() {
   
        if (instance == null) {
   
            synchronized (Singleton.class) {
   
                if (instance == null) {
   
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
  • 优点:线程安全且性能较好。
  • 缺点:实现稍复杂。

    静态内部类

    public class Singleton {
         
      private Singleton() {
         }
    
      private static class SingletonHolder {
         
          private static final Singleton INSTANCE = new Singleton();
      }
    
      public static Singleton getInstance() {
         
          return SingletonHolder.INSTANCE;
      }
    }
    
  • 优点:线程安全,延迟加载,实现简单。
  • 因为实例的创建由 JVM 在类加载时完成,且静态内部类的加载是线程安全的。
  • 实例在第一次调用 getInstance() 时创建。
  • 延迟加载(Lazy Initialization),只有在需要时才创建实例。

    枚举

    public enum Singleton {
         
      INSTANCE;
    
      public void doSomething() {
         
          // 业务逻辑
      }
    }
    
  • 优点:线程安全,防止反射攻击,简洁。

二、单例模式在框架源码中的运用

Java 标准库 RunTime类

Runtime 类Runtime 类是典型的单例模式实现,用于管理应用程序的运行环境。

public class Runtime {
   
    private static final Runtime currentRuntime = new Runtime();
    private Runtime() {
   }
    public static Runtime getRuntime() {
   
        return currentRuntime;
    }
}
  • 通过 Runtime.getRuntime() 获取唯一的 Runtime 实例。

Spring Framework

Spring 框架中的单例模式主要用于管理 Bean 的生命周期。
Spring 的默认 Bean 作用域

  • Spring 容器中的 Bean 默认是单例的(Singleton 作用域),即每个 Spring 容器中只有一个实例。
    ```java
    @Service
    public class UserService {
    // UserService 在 Spring 容器中是单例的
    }

@Service
@Scope("singleton") // 默认就是单例,可以省略
public class UserService {
}
```
单例 Bean 的管理

  • Spring 容器通过单例模式确保全局唯一的 Bean 实例,避免重复创建。
  • 示例:Spring 的 ApplicationContext 本身就是单例的。

三、总结

单例模式的优点

  1. 全局唯一访问点
    • 单例模式确保一个类只有一个实例,并提供一个全局访问点,方便其他模块或组件共享该实例。
    • 示例:配置管理器、日志记录器等。
  2. 节省资源
    • 对于创建成本高的对象(如数据库连接池、线程池),单例模式可以避免重复创建和销毁,节省系统资源。
    • 示例:数据库连接池通常只需要一个实例来管理所有连接。
  3. 保持一致性
    • 单例模式确保全局状态的一致性,避免多个实例导致状态冲突。
    • 示例:缓存管理器需要确保缓存数据的一致性。
  4. 简化设计
    • 单例模式可以减少对象创建的复杂性,使代码更简洁。
    • 示例:Spring 框架中的单例 Bean 管理。
  5. 线程安全(某些实现)
    • 通过正确的实现(如饿汉式、静态内部类、枚举),单例模式可以保证线程安全。

单例模式的缺点

  1. 难以扩展
    • 单例模式通常通过私有构造函数限制实例化,导致难以扩展或修改。
    • 如果需要多个实例或修改单例行为,可能需要重构代码。
  2. 隐藏依赖
    • 单例模式通过全局访问点获取实例,可能导致代码的依赖关系不清晰,增加调试和维护难度。
  3. 测试困难
    • 单例模式的全局状态可能导致单元测试困难,因为测试用例之间可能会相互影响。
    • 示例:测试一个依赖单例类的模块时,可能需要重置单例状态。
  4. 可能滥用
    • 单例模式容易被滥用,导致系统中出现大量全局状态,增加代码的耦合性。
  5. 生命周期管理问题
    • 单例模式的生命周期通常与应用程序一致,可能导致资源无法及时释放。
    • 示例:单例对象持有数据库连接,可能导致连接无法关闭。

单例模式的适用场景

  1. 全局唯一对象
    • 需要全局唯一的对象时,可以使用单例模式。
    • 示例:
      • 配置管理器(ConfigManager)。
      • 日志记录器(Logger)。
      • 数据库连接池(DataSource)。
  2. 资源密集型对象
    • 对于创建成本高的对象,单例模式可以避免重复创建和销毁。
    • 示例:
      • 线程池(ThreadPool)。
      • 缓存管理器(CacheManager)。
  3. 共享状态管理
    • 需要全局共享状态时,可以使用单例模式。
    • 示例:
      • 计数器(Counter)。
      • 全局锁(Lock)。
  4. 工具类
    • 对于无状态的工具类,单例模式可以避免重复创建实例。
    • 示例:
      • 日期格式化工具(DateUtils)。
      • 字符串处理工具(StringUtils)。
  5. 框架核心组件
    • 在框架中,单例模式常用于管理核心组件。
    • 示例:
      • Spring 的 ApplicationContext
      • MyBatis 的 SqlSessionFactory
目录
相关文章
|
4月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
112 16
|
4月前
|
设计模式 JavaScript Java
【设计模式】【创建型模式】原型模式(Prototype)
一、入门 什么是原型模式? 原型模式(Prototype Pattern)是一种创建型设计模式,它通过复制现有对象来创建新对象,而不是通过实例化类。 原型模式的核心是克隆(Clone),即通过复制现有
153 15
|
4月前
|
设计模式 Java Apache
【设计模式】【创建型模式】建造者模式(Builder)
一、入门 什么是建造者模式? 建造者模式(Builder Pattern)是一种创建型设计模式,用于逐步构建复杂对象。 它通过将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。 为什么
179 14
|
4月前
|
设计模式 Java 关系型数据库
【设计模式】【创建型模式】抽象工厂模式(Abstract Factory)
一、入门 什么是抽象工厂模式? 抽象工厂模式是一种创建型设计模式,它提供了一个接口,用于创建相关或依赖对象的家族,而不需要指定具体的类。 简单来说,抽象工厂模式是工厂方法模式的升级版,它能够创建一组相
147 14
|
5月前
|
设计模式 存储 安全
设计模式-单例模式练习
单例模式是Java设计模式中的重要概念,确保一个类只有一个实例并提供全局访问点。本文详解单例模式的核心思想、实现方式及线程安全问题,包括基础实现(双重检查锁)、懒汉式与饿汉式对比,以及枚举实现的优势。通过代码示例和类图,深入探讨不同场景下的单例应用,如线程安全、防止反射攻击和序列化破坏等,展示枚举实现的简洁与可靠性。
99 0
|
6月前
|
设计模式 XML Java
设计模式觉醒系列(03)创建型模式的5个设计模式 | 一口气讲全讲透
本文详细介绍了设计模式中的创建型模式,包括建造者模式、原型模式、单例模式、工厂方法模式和抽象工厂模式。创建型模式关注对象的创建过程,隐藏了创建细节,以提高代码的可维护性和可扩展性。通过具体的实战demo和应用场景分析,展示了每种模式的特点和优势。例如,建造者模式适用于复杂对象的分步骤构建;原型模式通过复制对象实现高效复用;单例模式确保全局唯一实例;工厂方法模式和抽象工厂模式则提供了灵活的对象创建机制,支持多类型产品族的生产。这些模式在实际开发中能够简化客户端代码,提升系统灵活性和复用性。
|
6月前
|
设计模式 安全 Java
设计模式:单例模式
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。它通过私有化构造函数、自行创建实例和静态方法(如`getInstance()`)实现。适用于数据库连接池、日志管理器等需要全局唯一对象的场景。常见的实现方式包括饿汉式、懒汉式、双重检查锁、静态内部类和枚举。线程安全问题可通过`synchronized`或双重检查锁解决,同时需防止反射和序列化破坏单例。优点是避免资源浪费,缺点是可能增加代码耦合度和测试难度。实际开发中应优先选择枚举或静态内部类,避免滥用单例,并结合依赖注入框架优化使用。
|
7月前
|
设计模式 存储 安全
设计模式2:单例模式
单例模式是一种创建型模式,确保一个类只有一个实例,并提供全局访问点。分为懒汉式和饿汉式: - **懒汉式**:延迟加载,首次调用时创建实例,线程安全通过双重检查锁(double check locking)实现,使用`volatile`防止指令重排序。 - **饿汉式**:类加载时即创建实例,线程安全但可能浪费内存。 示例代码展示了如何使用Java实现这两种模式。
96 4
|
4月前
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
117 0
|
4月前
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
92 0