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

news/2025/2/24 16:44:25

👋hi,我不是一名外包公司的员工,也不会偷吃茶水间的零食,我的梦想是能写高端CRUD
🔥 2025本人正在沉淀中… 博客更新速度++
👍 欢迎点赞、收藏、关注,跟上我的更新节奏
🎵 当你的天空突然下了大雨,那是我在为你炸乌云

文章目录

一、入门

什么是单例模式

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

为什么要单例模式

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

如何实现单例模式

  1. 私有构造函数:防止外部通过 new 创建实例。
  2. 静态私有实例:类内部持有唯一的实例。
  3. 静态公有方法:提供全局访问点,返回唯一实例。
    饿汉式
java">public class Singleton {
    // 在类加载时就创建实例
    private static final Singleton INSTANCE = new Singleton();

    // 私有构造函数,防止外部通过 new 创建实例
    private Singleton() {}

    // 提供全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}
  • 实例在类加载时立即创建。
  • 无论是否使用,实例都会提前初始化。

特点

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

懒汉式

java">public class Singleton {
    private static Singleton instance;

    private Singleton() {}

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

双重检查(DCL)

java">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;
    }
}
  • 优点:线程安全且性能较好。
  • 缺点:实现稍复杂。

静态内部类

java">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),只有在需要时才创建实例。

枚举

java">public enum Singleton {
    INSTANCE;

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

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

Java 标准库 RunTime类

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

java">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

http://www.niftyadmin.cn/n/5864598.html

相关文章

centos7中Open-Webui的部署

前期中部署了ollama 及deepseek-r1,为了有web界面访问,需要部署open-webui 系统要求是python3.11以上版本, 一、先升级openssl 1.安装依赖 yum install -y gcc gcc-c autoconf automake zlib zlib-devel pcre-devel 2.下载源码包并解压 wget https:/…

基于springboot+vue的考研互助平台

开发语言:Java框架:springbootJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包:…

基于跨学科任务图谱和大模型微调的智能体设计

技术方案:基于跨学科任务图谱和大模型微调的智能体设计 1. 跨学科任务图谱生成 1.1 降噪与补齐 降噪 跨学科任务图谱的生成首先要对原始数据进行降噪处理,以消除不必要的干扰信息。假设原始数据为 ( D ),降噪后的数据为 ( D’ ),降噪过程可以通过以下公式表示: [ D’…

2016年下半年试题二:论软件设计模式及其应用

论文库链接:系统架构设计师论文 论文题目 软件设计模式(Software DesignPatter)是一套被反复使用的、多数人知晓的、经过分类编目的代码设计经验的总结。使用设计模式是为了重用代码以提高编码效率增加代码的可理解性、保证代码的可靠性。软件设计模式是软件开发中的…

案例自定义tabBar

1.通过Vannt Weapp组件库,引用一个tabBar组件实现自定义tabBar基本模板 2.实现自定义图标 3.渲染tabBar上的数字徽标 下面这张图可以看到设置的样式并没有生效 根据文档可知需要 这一步需要把store中的sum值给绑到徽标上 4.实现tabBar的切换效果 解决底部选中项索引…

JavaScript函数-函数的返回值

在JavaScript编程语言中,函数是构建复杂逻辑和实现代码复用的关键组件。而函数的返回值则是这些功能的重要组成部分,它允许我们将数据从一个函数传递到另一个地方,从而使得函数更加通用和灵活。本文将深入探讨JavaScript函数返回值的各种特性…

自签SSL实现https

首先下载安装openssl,网址如下: https://slproweb.com/products/Win32OpenSSL.html 自签名证书生成及 Nginx HTTPS 配置教程 本教程将指导你如何生成自签名证书,并在 Nginx 中配置 HTTPS 服务。以下是详细步骤: 1. 生成加密的私…

go 语言中的线程池

使用 goroutine 和 channel Go 语言中并没有直接类似 Java 线程池的内建概念,但它提供了类似的功能,主要通过goroutine和channel来实现并发处理。你可以通过结合这两者来实现一个“线程池”的功能。 在 Go 中,goroutine是轻量级的线程&…