Java二十三种设计模式-单例模式(1/23)
引言
在软件开发中,设计模式是一套被反复使用的、大家公认的、经过分类编目的代码设计经验的总结。单例模式作为其中一种创建型模式,确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的概念、实现方式、使用场景以及潜在的问题。

基础知识,java设计模式总体来说设计模式分为三大类:
(1)创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
(2)结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
(3)行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

第一部分:单例模式概述
1.1 单例模式定义
单例模式是一种常用的软件设计模式,其核心思想是确保一个类在任何情况下都只有一个实例,并且提供一个全局访问点来获取这个唯一的实例。这种模式在需要全局状态信息或者需要频繁创建和销毁实例会导致资源浪费的情况下非常有用。
为什么需要单例模式?
- 全局访问点:在某些情况下,我们需要一个全局的访问点来操作某些资源或状态,例如配置信息管理器或数据库连接池。
- 资源优化:避免创建多个实例导致的资源浪费,例如线程池或缓存。
- 控制状态:在多线程环境下,控制对共享资源的并发访问,确保数据的一致性。
1.2 单例模式的特点
懒汉式单例模式
懒汉式单例模式的核心特点是“按需实例化”,即只有在第一次调用getInstance()方法时才会创建实例。
特点:
- 延迟加载:只有在真正需要使用实例时才进行加载,可以提高系统启动速度。
- 线程不安全:在多线程环境下,如果没有适当的同步措施,可能会导致多个实例被创建。
示例代码(不同步):
public class LazySingleton {private static LazySingleton instance;private LazySingleton() {}public static LazySingleton getInstance() {if (instance == null) {instance = new LazySingleton();}return instance;}
}
饿汉式单例模式
与懒汉式相对,饿汉式单例模式在类加载时就立即创建实例。
特点:
- 线程安全:由于实例在类加载时就已经创建,因此不存在多线程同步问题。
- 资源浪费:如果实例从未被使用,也会造成资源浪费。
示例代码:
public class EagerSingleton {private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {}public static EagerSingleton getInstance() {return instance;}
}
线程安全和线程不安全的单例模式
- 线程安全的单例模式:通过同步机制确保在多线程环境下,
getInstance()方法不会被多次调用,从而创建多个实例。 - 线程不安全的单例模式:没有采取同步措施,可能会在多线程环境下创建多个实例。
线程安全的实现示例(双重检查锁定):
public class ThreadSafeSingleton {private static volatile ThreadSafeSingleton instance;private ThreadSafeSingleton() {}public static ThreadSafeSingleton getInstance() {if (instance == null) {synchronized (ThreadSafeSingleton.class) {if (instance == null) {instance = new ThreadSafeSingleton();}}}return instance;}
}
在这部分内容中,我们介绍了单例模式的基本定义和两种主要的实现方式:懒汉式和饿汉式。接下来,我们将深入探讨单例模式的实现细节和使用场景。
第二部分:单例模式的实现
2.1 懒汉式单例模式
代码示例:
public class LazySingleton {// volatile关键字确保多线程环境下的内存可见性private static volatile LazySingleton instance;private LazySingleton() {// 防止通过反射攻击单例模式if (instance != null) {throw new IllegalStateException("Instance already exists!");}}public static LazySingleton getInstance() {// 双重检查锁定,减少不必要的同步if (instance == null) {synchronized (LazySingleton.class) {if (instance == null) {instance = new LazySingleton();}}}return instance;}
}
优点和缺点:
-
优点:
- 按需创建实例,节省资源。
- 简单易懂,实现容易。
-
缺点:
- 线程安全性需要额外处理,如示例中的双重检查锁定。
- 反射和序列化可能破坏单例模式。
2.2 饿汉式单例模式
代码示例:
public class EagerSingleton {// 静态初始化,类装载时就完成实例化private static final EagerSingleton instance = new EagerSingleton();private EagerSingleton() {// 防止通过反射攻击单例模式if (instance != null) {throw new IllegalStateException("Instance already exists!");}}public static EagerSingleton getInstance() {return instance;}
}
优点和缺点:
-
优点:
- 线程安全,无需额外同步。
- 实现简单。
-
缺点:
- 无论是否使用,类装载时就完成实例化,可能导致资源浪费。
- 可能影响类装载时间。
2.3 线程安全的单例模式
双重检查锁定(Double-Checked Locking)
-
代码示例:
public class DoubleCheckedLockingSingleton {private static volatile DoubleCheckedLockingSingleton instance;private DoubleCheckedLockingSingleton() {// 防止通过反射攻击单例模式if (instance != null) {throw new IllegalStateException("Instance already exists!");}}public static DoubleCheckedLockingSingleton getInstance() {if (instance == null) {synchronized (DoubleCheckedLockingSingleton.class) {if (instance == null) {instance = new DoubleCheckedLockingSingleton();}}}return instance;} } -
解释: 双重检查锁定首先检查实例是否存在,如果不存在,则进入同步块再次检查。这样避免了每次调用
getInstance()时都要进行同步,提高了性能。
静态内部类
-
代码示例:
public class StaticInnerClassSingleton {private StaticInnerClassSingleton() {// 防止通过反射攻击单例模式if (InstanceHelper.INSTANCE != null) {throw new IllegalStateException("Instance already exists!");}}private static class InstanceHelper {private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();}public static StaticInnerClassSingleton getInstance() {return InstanceHelper.INSTANCE;} } -
解释: 静态内部类利用了类装载的机制来保证初始化实例时的线程安全。静态内部类只有在第一次使用时才会装载,此时可以完成对单例对象的初始化。

2.4 枚举实现单例模式
代码示例:
public enum EnumSingleton {// 实例化枚举INSTANCE;// 可以添加其他方法public void doSomething() {// ...}
}
优点:
- 自然实现单例: 枚举在Java语言中天然是单例的,每个枚举常量在JVM中只有一个实例。
- 线程安全: 枚举实例的创建是线程安全的。
- 防止反射和序列化攻击: 枚举类型本身可以防止反射和序列化攻击,因为枚举类型不允许通过反射创建枚举实例。
通过上述实现方式,我们可以看到单例模式的多样性和灵活性。每种实现方式都有其适用场景和优缺点,开发者需要根据实际情况选择最合适的实现方法。在下一部分中,我们将探讨单例模式的使用场景和潜在问题。

第三部分:单例模式的使用场景
单例模式因其确保唯一实例的特性,在软件系统中有多种应用场景。本节将讨论几个典型的使用案例。
3.1 数据库连接池
为什么数据库连接池适合使用单例模式?
数据库连接池管理着数据库连接的创建、使用和销毁过程,其目的是减少频繁创建和销毁连接的开销,提高资源利用率。
- 资源复用:单例模式确保连接池全局只有一个实例,所有需要数据库连接的部分都使用同一个池,避免了创建多个连接池带来的资源浪费。
- 统一管理:通过单例模式,可以集中管理数据库连接的生命周期,包括连接的创建、监控和销毁。
- 性能优化:数据库连接的创建是一个耗时的操作,单例模式使得连接池可以在系统启动时初始化,并在运行期间复用这些连接,从而提高系统性能。
3.2 配置管理器
讨论配置信息管理中使用单例模式的优势。
配置管理器负责存储和提供应用的配置信息,如数据库配置、服务地址等。
- 全局访问:单例模式提供了一个全局访问点,使得系统中所有需要配置信息的部分都能方便地获取到最新的配置数据。
- 数据一致性:确保所有部分使用的是同一个配置管理器实例,从而保证了配置数据的一致性。
- 简化配置更新:当配置信息发生变化时,只需更新单例配置管理器中的信息,所有依赖配置的地方都会获得更新后的数据。
3.3 硬件资源管理器
讨论硬件资源管理中使用单例模式的场景。
硬件资源管理器负责对打印机、扫描仪等硬件设备进行控制和访问管理。
- 设备控制:硬件设备通常希望被控制系统以单例模式管理,以避免多个实例同时发送指令造成冲突。
- 状态同步:单例模式可以确保所有对硬件状态的更改都是同步的,防止因多实例并发操作导致的状态不一致问题。
- 减少资源消耗:硬件资源通常有限,单例模式可以减少对这些资源的重复申请和占用。
在这些场景中,单例模式的应用可以带来诸多好处,包括资源优化、数据一致性保证以及简化的系统设计。然而,单例模式的使用也需慎重考虑,以避免其潜在的问题,如测试困难、扩展性限制等。在后续部分,我们将进一步探讨单例模式的潜在问题和最佳实践。
第四部分:单例模式的潜在问题
4.1 测试困难
单例模式可能会给单元测试带来一些挑战,因为它依赖于全局状态。
- 全局状态问题:单例模式提供了全局访问点,这可能导致测试之间的相互影响,使得测试结果不可预测。
- 模拟困难:在需要模拟或替换单例组件的行为时,由于其全局性,很难进行模拟(Mocking)。
- 解决方案:可以通过使用依赖注入、接口或者使用测试框架提供的特定技术来解决这些问题。
4.2 扩展性问题
随着系统的发展,单例模式可能会成为系统扩展的瓶颈。
- 紧耦合问题:单例模式可能使得系统组件之间存在紧耦合,这在需要扩展或修改单例组件时可能导致问题。
- 服务降级:在分布式系统中,单例模式可能不再适用,因为它无法很好地支持服务的横向扩展。
4.3 多线程环境问题
在多线程环境中使用单例模式时,需要特别注意线程安全问题。
- 竞态条件:如果多个线程同时访问单例实例的创建过程,而这个过程中没有适当的同步机制,可能会导致创建多个实例。
- 性能问题:过度的同步可能会降低系统性能,特别是在高并发场景下。
第五部分:单例模式与其他设计模式的比较
5.1 单例模式与工厂模式
单例模式和工厂模式都涉及到类的实例化,但它们的目的和使用场景不同。
- 单例模式:确保一个类只有一个实例,并提供一个全局访问点。
- 简单工厂模式:创建对象的接口,让子类决定实例化哪一个类。
5.2 单例模式与原型模式
原型模式提供了通过复制现有的实例来创建新实例的能力,与单例模式形成对比。
- 单例模式:关注于限制实例的数量,确保全局只有一个实例。
- 原型模式:关注于通过复制来快速创建新实例,适用于创建复杂对象。
第六部分:最佳实践和建议
6.1 何时使用单例模式
单例模式适用于管理共享资源,如配置信息、连接池等。
- 全局状态管理:当全局状态需要被整个应用共享时。
- 资源优化:当创建多个实例会导致资源浪费时。
6.2 避免滥用单例模式
滥用单例模式可能导致代码难以测试和维护。
- 避免全局状态:尽量减少依赖全局状态,因为它可能导致代码难以理解和测试。
- 替代方案:考虑使用依赖注入等技术来减少对单例模式的依赖。
6.3 替代方案
依赖注入是一种常用的替代单例模式的技术。
- 依赖注入:通过依赖注入框架,可以将对象的创建和管理交给框架来处理,从而减少对单例模式的依赖。
- 服务定位器模式:提供了一种查找服务的方式,可以作为单例模式的替代方案。
通过深入分析单例模式的潜在问题和最佳实践,我们可以更明智地决定何时以及如何使用单例模式。在实际开发中,我们应该根据具体需求和上下文来选择最合适的设计模式。

结语
单例模式是一种简单但强大的设计模式,正确使用可以带来诸多好处,但也需要谨慎处理以避免潜在问题。通过本文的深入分析,希望读者能够对单例模式有更全面的理解,并在实际开发中做出合理的设计选择。
相关文章:
Java二十三种设计模式-单例模式(1/23)
引言 在软件开发中,设计模式是一套被反复使用的、大家公认的、经过分类编目的代码设计经验的总结。单例模式作为其中一种创建型模式,确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的概念、实现方式、使用场景以及潜…...
Unity动画系统(3)---融合树
6.1 动画系统基础2-6_哔哩哔哩_bilibili Animator类 using System.Collections; using System.Collections.Generic; using UnityEngine; public class EthanController : MonoBehaviour { private Animator ani; private void Awake() { ani GetComponen…...
sqlalchemy.orm中validates对两个字段进行联合校验
版本 sqlalchemy1.4.37 需求说明 有个场景,需要在orm中对两个字段进行联合校验,当 col1 xxx’时,对 col2的长度进行检查,超过限制(500)时,进行截断。 网上找了很久,没找到类似的…...
【ROS2】高级:解锁 Fast DDS 中间件的潜力 [社区贡献]
目标:本教程将展示如何在 ROS 2 中使用 Fast DDS 的扩展配置功能。 教程级别:高级 时间:20 分钟 目录 背景 先决条件在同一个节点中混合同步和异步发布 创建具有发布者的节点创建包含配置文件的 XML 文件执行发布者节点创建一个包含订阅者的节…...
VirtualBox虚拟机与主机互传文件的方法
建立共享文件夹 1.点击设置,点击共享文件夹,添加共享文件夹路径,保存 2.启动虚拟机,点击设备,点击安装增强功能,界面会出现一个光碟图标,点击光碟图标 3.打开光碟图标,出现一个目…...
访问控制系列
目录 一、基本概念 1.客体与主体 2.引用监控器与引用验证机制 3.安全策略与安全模型 4.安全内核 5.可信计算基 二、访问矩阵 三、访问控制策略 1.主体属性 2.客体属性 3.授权者组成 4.访问控制粒度 5.主体、客体状态 6.历史记录和上下文环境 7.数据内容 8.决策…...
【BUG】已解决:ModuleNotFoundError: No module named ‘cv2’
已解决:ModuleNotFoundError: No module named ‘cv2’ 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,211科班出身,就职于医疗科技公司,热衷分享知识,武汉城市开…...
成都亚恒丰创教育科技有限公司 【插画猴子:笔尖下的灵动世界】
在浩瀚的艺术海洋中,每一种创作形式都是人类情感与想象力的独特表达。而插画,作为这一广阔领域中的璀璨明珠,以其独特的视觉语言和丰富的叙事能力,构建了一个又一个令人遐想连篇的梦幻空间。成都亚恒丰创教育科技有限公司 在众多插…...
gite+picgo+typora打造个人免费笔记软件
文章目录 1️⃣个人笔记软件2️⃣ 配置教程2.1 使用软件2.2 node 环境配置2.3 软件安装2.4 gite仓库设置2.5 配置picgo2.6 测试检验2.7 github教程 🎡 完结撒花 1️⃣个人笔记软件 最近换了环境,没有之前的生产环境舒适,写笔记也没有劲头&…...
只用 CSS 能玩出什么花样?
在前端开发领域,CSS 不仅仅是一种样式语言,它更像是一位多才多艺的艺术家,能够创造出令人惊叹的视觉效果。本文将带你探索 CSS 的无限可能,从基本形状到动态动画,从几何艺术到仿生设计,只用 CSS 就能玩出令…...
Linux C++ 056-设计模式之迭代器模式
Linux C 056-设计模式之迭代器模式 本节关键字:Linux、C、设计模式、迭代器模式 相关库函数: 概念 迭代器模式(Iterator Pattern)是一种常用的设计模式。迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而…...
【Elasticsearch7.11】reindex问题
参考博文链接 问题:reindex 时出现如下问题 原因:数据量大,kibana的问题 解决方法: 将DSL命令转化成CURL命令在服务上执行 CURL命令 自动转化 curl -XPOST "http://IP:PORT/_reindex" -H Content-Type: application…...
nginx代理缓存
在服务器架构中,反向代理服务器除了能够起到反向代理的作用之外,还可以缓存一些资源,加速客户端访问,nginx的ngx_http_proxy_module模块不仅包含了反向代理的功能还包含了缓存功能。 1、定义代理缓存规则 参数详解: p…...
[React 进阶系列] useSyncExternalStore hook
[React 进阶系列] useSyncExternalStore hook 前情提要,包括 yup 的实现在这里:yup 基础使用以及 jest 测试 简单的提一下,需要实现的功能是: yup schema 需要访问外部的 storage外部的 storage 是可变的React 内部也需要访问同…...
Linux C++ 055-设计模式之状态模式
Linux C 055-设计模式之状态模式 本节关键字:Linux、C、设计模式、状态模式 相关库函数: 概念 状态模式(State Pattern)是设计模式的一种,属于行为模式。允许一个对象在其内部状态改变时改变它的行为。对象看起来似…...
景联文科技构建高质量心理学系知识图谱,助力大模型成为心理学科专家
心理大模型正处于快速发展阶段,在临床应用、教育、研究等多个领域展现出巨大潜力。 心理学系知识图谱能够丰富心理大模型的认知能力,使其在处理心理学相关问题时更加精确、可靠和有洞察力。这对于提高心理健康服务的质量和效率、促进科学研究以及优化教育…...
【数学建模】——数学规划模型
目录 一、线性规划(Linear Programming) 1.1 线性规划的基本概念 1.2 线性规划的图解法 模型建立: 二、整数规划(Integer Programming) 2.1 整数规划的基本概念 2.2 整数规划的求解方法 三、非线性规划&#x…...
卸载linux 磁盘的内容,磁盘占满
Linux清理磁盘 https://www.cnblogs.com/siyunianhua/p/17981758 当前文件夹下,数量 ls -l | grep "^-" | wc -l ls -lR | grep "^-" | wc -l 找超过100M的大文件 find / -type f -size 100M -exec ls -lh {} \; df -Th /var/lib/docker 查找…...
LeetCode-随机链表的复制
. - 力扣(LeetCode) 本题思路: 首先注意到随机链表含有random的指针,这个random指针指向是随机的;先一个一个节点的拷贝,并且把拷贝的节点放在拷贝对象的后面,再让拷贝节点的next指向原链表拷贝…...
axios 下载大文件时,展示下载进度的组件封装——js技能提升
之前面试的时候,有遇到一个问题:就是下载大文件的时候,如何得知下载进度,当时的回复是没有处理过。。。 现在想到了。axios中本身就有一个下载进度的方法,可以直接拿来使用。 下面记录一下处理步骤: 参考…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?
Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以? 在 Golang 的面试中,map 类型的使用是一个常见的考点,其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
