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中本身就有一个下载进度的方法,可以直接拿来使用。 下面记录一下处理步骤: 参考…...
Linux: network: device事件注册机制 chatGPT; notify
ChatGPT 在 Linux 内核中,有关网络设备(net-device)的事件注册机制,允许用户在网络设备的状态发生变化(例如设备被删除、添加或修改)时接收通知。这主要通过 netdev 事件通知机制实现。具体来说,内核提供了一组用于注册和处理网络设备事件的 API。 以下是一些关键组件…...
【ROS2】测试
为什么要进行自动化测试? 以下是我们应该进行自动化测试的许多重要原因之一: 您可以更快地对代码进行增量更新。ROS 有数百个包,具有许多相互依赖关系,因此很难预见一个小变化可能引起的问题。如果您的更改通过了单元测试…...
别卷模型,卷应用:从李彦宏的AI观点谈起
2024年7月4日,世界人工智能大会暨人工智能全球治理高级别会议在上海世博中心隆重召开。百度创始人、董事长兼首席执行官李彦宏在产业发展主论坛上的发言,引起了广泛关注。他提出:“大家不要卷模型,要卷应用!”这一观点…...
数据库(Database,简称DB)介绍
数据库(Database,简称DB)是信息技术领域中一个至关重要的组成部分,它按照数据结构来组织、存储和管理数据。以下是对数据库的详细介绍: 一、定义与基本概念 定义:数据库是按照数据结构来组织、存储和管理…...
Redis五种常用数据类型详解及使用场景
Redis 5 种基本数据类型 Redis 共有 5 种基本数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。 这 5 种数据类型…...
Postman API测试覆盖率:全面评估指南
📊 Postman API测试覆盖率:全面评估指南 在API测试中,测试覆盖率是一个关键指标,它衡量了测试用例对代码的覆盖程度。Postman提供了多种工具和方法来评估API测试覆盖率,帮助开发者和测试人员确保API的质量和稳定性。本…...
C++--find
find 在[first,last)区间找第一个等于val的元素。 template<class InputIterator, class T> InputIterator find(InputIterator first,//起始迭代器 InputIterator last, //结束迭代器 const T& val); //需要查找的值 源码剖析 template<class InputI…...
JavaWeb入门程序解析(Spring官方骨架、配置起步依赖、SpringBoot父工程、内嵌Tomcat)
3.3 入门程序解析 关于web开发的基础知识,我们可以告一段落了。下面呢,我们在基于今天的核心技术点SpringBoot快速入门案例进行分析。 3.3.1 Spring官方骨架 之前我们创建的SpringBoot入门案例,是基于Spring官方提供的骨架实现的。 Sprin…...
mysql命令练习
创建数据表grade: CREATE TABLE grade( id INT NOT NULL, sex CHAR(1), firstname VARCHAR(20) NOT NULL, lastname VARCHAR(20) NOT NULL, english FLOAT, math FLOAT, chinese FLOAT ); 向数据表grade中插…...
AI绘画Stable Diffusion 零基础入门 —AI 绘画原理与工具介绍,万字解析AI绘画的使用教程
大家好,我是设计师阿威 想要入门 AI 绘画,首先需要了解它的原理是什么样的。 其实很早就已经有人基于深度学习模型展开了对图像生成的研究了,但在那时,生成的图像分辨率和内容都非常抽象。 直到近两年,AI 产出的图像…...
网站普查建设背景/网站建设企业建站
文章目录系统配置PDF 转 HTMLpdf2htmlEXpdf2htmlPDFBoxaspose-wordsPDF 转 TXTaspose-wordspypdf2PDF 转 docxpdf2docx其他系统配置 Macos M1 pro PDF 转 HTML 首先给出的是不需要写任何代码就能成的 pdf2htmlEX 要将 PDF 文件转换为 HTML 文件,可以使用 pdf2h…...
wordpress移动端导航菜单/互联网推广的好处
今天想说的是不要让自己企业的信息化穿上“皇帝的新装”,从这几年的工作来看,以安全为例,安全对于大家来说越来越受到重视,从国家政策及舆论层面每日剧增,信息安全或者说网络安全没有绝对安全%100安全,企业…...
用什么软件做动漫视频网站好/专业网络推广外包
在华清星创客高级班里学习51单片机的时候,经常会使用keilprotues的方式来做一些实验,这样的模拟仿真为我们节省了很多硬件和时间成本,可以更直观的看到代码的执行过程。那么当切换到stm32系列单片机的时候,protues明显不支持了&am…...
网站备案安全承诺书/爱站网关键词长尾挖掘工具
设向量a和向量b 则a•b|a||b|cos,|a|和|b|分别为两向量的模 cos即为两向量的余弦值,所以cosa•b/|a||b| 距离和相似性度量: http://blog.sina.com.cn/s/blog_6045a9da01011nk7.html 转载于:https://www.cnblogs.com/lsai/p/3715948.html...
php网站建设流程/学seo如何入门
前段时间的帖子,利用TPYBoard v102做的DIY照相机,周末实物终于做出来了,加了两个按键模块和一个5110,做的有点糙啊----望大家勿怪,哈哈哈。拍出来图片还算清晰,串口摄像头模块用的30w像素的(贫穷…...
网站的栏目/如何做好线上推广和引流
目录 前言 正文 最后的话 前言 其实我之前振动噪声系列中,涉及气隙磁密的分析的,都是给一个推导的逻辑链,说什么知道磁动势了,知道气隙磁导了,就可以推出气隙磁密了。这话吧,不能说是错的,但…...