Java设计模式:单例模式详解
设计模式:单例详解
文章目录
- 设计模式:单例详解
- 一、单例模式的原理
- 二、单例模式的实现推荐
- 1、饿汉模式
- 2、静态内部类
- 三、单例模式的案例
- 四、单例模式的使用场景推荐
- 总结
一、单例模式的原理
单例模式听起来很高大上,但其实它的核心思想很简单,就是确保一个类只有一个实例,并提供一个全局访问点。单例模式的原理其实不难理解。想象一下,你有一个类,这个类负责某种特定的资源或功能,而这个资源或功能在整个应用程序中只需要一个实例就足够了。这时,你就可以使用单例模式来确保这个类只有一个实例,并且这个实例可以被整个应用程序访问。
要实现单例模式,通常需要做到以下几点:
- 私有化构造函数,防止外部通过new关键字创建实例。
- 提供一个静态的私有变量来保存类的唯一实例。
- 提供一个公共的静态方法来获取类的唯一实例,如果实例不存在则创建它。
二、单例模式的实现推荐
1、饿汉模式
饿汉式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。可能会造成一些资源的损失浪费,但是不需要开发者关心线程安全之类的问题。它有以下优点:
- 线程安全:由于实例的初始化在类加载时就完成了,因此它是线程安全的,多个线程同时调用getInstance()方法时,不会存在竞态条件。
- 简单明了:实现方式简单直观,易于理解。
代码示例:
public class Singleton { private Singleton() { // 私有化构造函数 } // 静态内部类 private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.INSTANCE; }
}
2、静态内部类
静态内部类利用JVM的类加载机制来保证初始化instance时只有一个线程,所以它是线程安全的,同时该实现方式也是延迟加载的,即类加载时不初始化,只有在第一次调用getInstance()方法时才初始化。它有以下优点:
- 线程安全:与饿汉式类似,由于使用了静态内部类,在类加载时并不会初始化INSTANCE,而是在第一次调用getInstance()方法时,由JVM来确保线程安全地初始化INSTANCE。
- 延迟加载:实现了懒汉式的延迟加载效果,只有在第一次真正需要使用单例时才进行初始化,节省了系统资源。
- 双重校验锁效果的简化实现:避免了复杂的双重校验锁实现,降低了出错的可能性,同时保持了线程安全。
静态内部类的实现结合了饿汉式的线程安全和懒汉式的延迟加载的优点,既保证了线程安全,又实现了延迟加载,是一种较为推荐的单例实现方式。
三、单例模式的案例
为了更好地理解单例模式,我们来看一个简单的案例。假设我们有一个配置管理类ConfigManager,这个类负责读取和提供应用程序的配置信息。由于配置信息在应用程序中是全局共享的,所以我们希望ConfigManager在整个应用程序中只有一个实例。
下面是一个简单的单例模式实现:
public class ConfigManager { // 静态的私有变量保存类的唯一实例 private static ConfigManager instance; // 私有化构造函数 private ConfigManager() { // 初始化代码 } // 公共的静态方法获取类的唯一实例 public static ConfigManager getInstance() { if (instance == null) { instance = new ConfigManager(); } return instance; } // 提供读取配置信息的方法 public String getConfigValue(String key) { // 实现读取配置的逻辑 return "value from config"; }
}
在上面的代码中,我们通过将构造函数私有化来防止外部直接创建ConfigManager的实例。然后,我们提供了一个公共的静态方法getInstance()来获取类的唯一实例。当第一次调用这个方法时,它会创建ConfigManager的实例并保存在instance变量中;之后再次调用时,就直接返回已经创建的实例。
四、单例模式的使用场景推荐
- 日志记录器:单例模式能够确保整个应用程序使用同一个日志记录器实例。这有助于统一管理和配置日志记录器的行为,包括日志级别、输出格式、存储位置等,使得日志信息能够按照预定的规范进行记录,方便后续的查看和分析。
- 配置管理类:在应用程序中,通常会有一些全局的配置信息,如数据库连接信息、系统参数等。这些配置信息在整个应用程序中都需要访问,且应该保持一致。通过使用单例模式,可以确保配置管理类只有一个实例,从而避免配置信息的重复加载和不一致问题。
- 数据库连接池:数据库连接是应用程序中经常使用的资源,频繁地创建和销毁数据库连接会消耗大量的系统资源,并可能导致性能问题。通过使用单例模式实现数据库连接池,可以确保整个应用程序使用一个共享的数据库连接池实例。这样,连接池可以管理一定数量的数据库连接,并根据需要进行复用,从而提高系统性能和响应速度。
- 线程池:线程是应用程序中执行任务的基本单位。频繁地创建和销毁线程会浪费系统资源,并可能导致线程管理混乱。通过使用单例模式实现线程池,可以管理和复用线程资源,减少线程的创建和销毁开销。线程池可以维护一定数量的线程,并根据任务需求进行调度和执行,从而提高系统的并发性能和响应速度。
- SpringBoot使用单例模式:在Spring Boot框架中,单例模式得到了广泛的应用。通过使用@Component、@Service、@Controller等注解,可以将Bean托管到Spring的容器中进行管理。这些注解标识的类在Spring容器中默认是单例的,即整个Spring IoC容器中只会存在一个实例。这种管理方式简化了对象的创建和管理,使得开发者可以更加专注于业务逻辑的实现,而无需关心对象的生命周期和依赖关系。
单例模式的使用场景非常广泛,除了上述列的之外,还有如缓存管理、消息队列、定时任务管理等。然而,需要注意的是,虽然单例模式在某些场景下非常有用,但它并不适用于所有情况。在设计系统时,应根据具体需求和场景来选择合适的设计模式,以确保系统的可维护性、可扩展性和性能。
总结
通过掌握单例模式的原理、案例和使用场景,我们可以更加灵活地运用它来解决实际开发中的问题。希望这篇文章能够帮助大家更好地理解和应用单例模式,为后续的Java学习和实践打下坚实的基础。
相关文章:
Java设计模式:单例模式详解
设计模式:单例详解 文章目录 设计模式:单例详解一、单例模式的原理二、单例模式的实现推荐1、饿汉模式2、静态内部类 三、单例模式的案例四、单例模式的使用场景推荐总结 一、单例模式的原理 单例模式听起来很高大上,但其实它的核心思想很简…...
Qt5.14.2 定时器黑魔法,一键唤醒延时任务
在图形界面程序的世界里,有这么一个需求无处不在:在特定的时间间隔后,执行一段特殊的代码。比如说30秒后自动保存文档、500毫秒后更新UI界面等等。作为资深Qt程序员,我相信各位一定也曾为实现这种"延时任务"而绞尽脑汁。今天&#…...

C++项目——集群聊天服务器项目(九)客户端异常退出业务
服务器端应检测到客户端是否异常退出,因此本节来实现客户端异常退出,项目流程见后文 一、客户端异常退出业务流程 (1)在业务模块定义处理客户端异常退出的函数 (2)集群聊天服务器项目(八)提到…...

STM32CubeIDE基础学习-HC05蓝牙模块和手机通信
STM32CubeIDE基础学习-HC05蓝牙模块和手机通信 文章目录 STM32CubeIDE基础学习-HC05蓝牙模块和手机通信前言第1章 硬件连接第2章 工程配置第3章 代码编写3.1 手机指令控制LED 第4章 实验现象总结 前言 前面的文章学习了串口通过轮询和中断的简单使用方法,现在就来用…...

npm mongoose包下载冲突解决之道
我在新电脑下载完项目代码后,运行 npm install --registryhttps://registry.npm.taobao.org 1运行就报错: npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree npm ERR! npm ERR! While resolving: lowcode-form-backend1.0.0 npm …...

26. UE5 RPG同步面板属性(二)
在上一篇,我们解析了UI属性面板的实现步骤: 首先我们需要通过c去实现创建GameplayTag,这样可以在c和UE里同时获取到Tag创建一个DataAsset类,用于设置tag对应的属性和显示内容创建AttributeMenuWidgetController实现对应逻辑 并且…...

五、postman基础使用案例
postman基础使用 相关案例【传递查询参数】【提交表单数据】【提交JSON数据】 注:postman⼀款⽀持调试和测试的⼯具,开发、测试⼯程师都可以使⽤。方法一般统一为:方法→请求头→请求体→断言 相关案例 【传递查询参数】 访问TPshop搜索商品的…...

Git合并利器:Vimdiff使用指南
使用 vimdiff 作为 Git 的合并工具确实可能会让新手感到困惑,但它是一个功能强大的工具,一旦掌握了它,就可以非常高效地进行代码合并和比较。以下是一个简短的教程,旨在帮助理解 vimdiff 的基本用法以及如何利用它来进行 Git 合并…...

阿里云2核4G服务器租用价格_30元3个月_165元一年_199元
阿里云2核4G服务器租用优惠价格,轻量2核4G服务器165元一年、u1服务器2核4G5M带宽199元一年、云服务器e实例30元3个月,活动链接 aliyunfuwuqi.com/go/aliyun 活动链接如下图: 阿里云2核4G服务器优惠价格 轻量应用服务器2核2G4M带宽、60GB高效…...

<QT基础(2)>QScrollArea使用笔记
项目需要设置单个检查的序列图像预览窗口,采用QScrollArea中加入QWidget窗口,每个窗口里面用Qlabel实现图像预览。 过程涉及两部分内容 引入QWidget 引入label插入图像(resize) 引入布局 组织 scrollArea内部自带Qwidget&#…...

springboot企业级抽奖项目业务四 (缓存预热)
缓存预热 为什么要做预热: 当活动真正开始时,需要超高的并发访问活动相关信息 必须把必要的数据提前加载进redis 预热的策略: 在msg中写一个定时任务 每分钟扫描一遍card_game表 把(开始时间 > 当前时间)&& (开始时间 < 当前时间1分钟)的活动及相…...

opejdk11 java 启动流程 java main方法怎么被jvm执行
java启动过程 java main方法怎么被jvm执行 java main方法是怎么被jvm调用的 1、jvm main入口 2、执行JLI_Launch方法 3、执行JVMInit方法 4、执行ContinueInNewThread方法 5、执行CallJavaMainInNewThread方法 6、创建线程执行ThreadJavaMain方法 7、执行ThreadJavaMain方法…...

link 样式表是否会阻塞页面内容的展示?取决于浏览器,edge 和 chrome 会,但 firefox 不会。
经过实测: 在 head 中 link 一个 1M 大小的样式表。设置网络下载时间大概为 10 秒。 edge 和 chrome 只有在下载完样式表后,页面上才会出现内容。而 firefox 可以直接先显示内容,然后等待样式表下载完成后再应用样式。 DOMContentLoaded 事…...

uniapp对接极光推送(国内版以及海外版)
勾选push,但不要勾选unipush 国内版 网址:极光推送-快速集成消息推送功能,提升APP运营效率 (jiguang.cn) 进入后台,并选择对应应用开始配置 配置安卓包名 以及ios推送证书,是否将生产证书用于开发环境选择是 ios推送证书…...

智慧城市数字孪生,综合治理一屏统览
现代城市作为一个复杂系统,牵一发而动全身,城市化进程中产生新的矛盾和社会问题都会影响整个城市系统的正常运转。智慧城市是应对这些问题的策略之一。城市工作要树立系统思维,从构成城市诸多要素、结构、功能等方面入手,系统推进…...

在Java中对SQL进行常规操作的通用方法
SQL通用方法 一、常规方法增删改查二、具体优化步骤1.准备工作2.getcon()方法,获取数据库连接对象3.closeAll()方法,关闭所有资源4.通用的增删改方法5.通用的查询方法6.动态查询语句 总结 一、常规方法增删改查 在常规方法中,我们在Java中对…...

JavaSE day16笔记 - string
第十六天课堂笔记 学习任务 Comparable接口★★★★ 接口 : 功能的封装 > 一组操作规范 一个抽象方法 -> 某一个功能的封装多个抽象方法 -> 一组操作规范 接口与抽象类的区别 1本质不同 接口是功能的封装 , 具有什么功能 > 对象能干什么抽象类是事物本质的抽象 &…...

java将文件转成流文件返回给前端
环境:jdk1.8,springboot2.5.3,项目端口号:9100 1.待转换的文件 一、路径 二、文件内容 2.controller中代码 package com.example.pdf.controller;import com.example.pdf.service.GetFileStreamService; import org.springframework.web.b…...

使用Node.js常用命令提高开发效率
Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,广泛用于构建服务器端应用程序和命令行工具。Node.js提供了丰富的命令和工具,可以帮助开发者更高效地开发应用程序。在日常开发中,除了Node.js本身的核心功能外,npm&#x…...

百度资源平台链接提交
百度资源平台是百度搜索引擎提供的一个重要工具,用于帮助网站主将自己的网站链接提交给百度搜索引擎,以便更快地被收录和展示在搜索结果中。以下将就百度资源平台链接提交的概念、操作方法以及其对网站收录和曝光的影响进行探讨: 什么是百度资…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...

内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献
Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译: ### 胃肠道癌症的发病率呈上升趋势,且有年轻化倾向(Bray等人,2018&#x…...
PostgreSQL 与 SQL 基础:为 Fast API 打下数据基础
在构建任何动态、数据驱动的Web API时,一个稳定高效的数据存储方案是不可或缺的。对于使用Python FastAPI的开发者来说,深入理解关系型数据库的工作原理、掌握SQL这门与数据库“对话”的语言,以及学会如何在Python中操作数据库,是…...