Java设计模式—单例模式(Singleton Pattern)

目录

一、定义 

二、应用场景 

三、具体实现

示例一

示例二

四、懒汉与饿汉

饿汉模式

懒汉模式

五、总结

六、说明


一、定义 

二、应用场景 

‌单例模式的应用场景主要包括以下几个方面:

  1. ‌日志系统:在应用程序中,通常只需要一个日志系统,通过单例模式可以避免在多个地方创建多个日志对象,降低资源消耗。‌

  2. ‌数据库连接池:数据库连接池是一个重要的资源,使用单例模式可以确保应用程序中只有一个数据库连接池实例,从而避免资源浪费。

  3. ‌配置文件管理器:为了管理应用程序的配置文件,通常只需要一个配置文件管理器实例。单例模式可以确保整个应用程序中只有一个配置文件管理器实例。

  4. ‌缓存系统:缓存系统是提高应用程序性能的关键组件,使用单例模式可以确保整个应用程序中只有一个缓存实例。

  5. ‌GUI组件:在图形用户界面(GUI)开发中,单例模式可以确保整个应用程序中只有一个GUI组件实例,以保持用户界面的一致性和稳定性。

  6. ‌读取配置信息:如果配置信息需要在程序启动时加载,并且只需读取一次,那么可以使用单例模式来读取配置文件。‌

此外,单例模式还适用于那些创建对象时资源消耗大,但又需要频繁访问该对象的场景,或者需要对系统内的资源进行统一的读写操作的场景,比如进行配置文件的读写操作。‌

总的来说,单例模式通常适用于在整个应用程序中只需要一个实例化对象的场景,以确保资源的高效利用和应用程序的稳定性。

三、具体实现

示例一

“ 需求:对于项目中的 JSON 要格式化处理对象,采用 双检锁单例模式 进行管理,从而复用对象,避免重复创建对象的开销 ”

实现:

创建单例:

import com.fasterxml.jackson.databind.ObjectMapper;// JsonFormatter 类负责管理 ObjectMapper 对象,它是 Jackson 库中用于处理 JSON 的核心类。public class JsonFormatter {private static volatile JsonFormatter instance;private ObjectMapper objectMapper;// 私有构造方法,防止外部实例化private JsonFormatter() {// 初始化 ObjectMapperobjectMapper = new ObjectMapper();// 可以在这里配置 ObjectMapper 的特性,例如日期格式化、空字段处理等}// 获取单例实例的静态方法
// 使用双检锁(double-checked locking)来确保在多线程环境下只创建一个 JsonFormatter 实例。public static JsonFormatter getInstance() {if (instance == null) {
//volatile 关键字确保在多线程环境中正确地处理 instance 变量,防止指令重排序带来的问题。synchronized (JsonFormatter.class) {if (instance == null) {instance = new JsonFormatter();}}}return instance;}// 提供了一个公共方法来格式化 JSON 字符串,可以将对象转换为 JSON 格式的字符串。public String formatJson(Object obj) {try {return objectMapper.writeValueAsString(obj);} catch (Exception e) {e.printStackTrace();return null;}}
}

 使用单例:

public class MyApp {public static void main(String[] args) {JsonFormatter jsonFormatter = JsonFormatter.getInstance();// 示例对象MyObject obj = new MyObject("John Doe", 30);// 格式化为 JSON 字符串String jsonString = jsonFormatter.formatJson(obj);System.out.println("Formatted JSON: " + jsonString);}
}

 

         使用双检锁单例模式来管理 JSON 格式化处理对象,确保在整个项目中只有一个 JsonFormatter 实例存在,避免了重复创建对象的开销,同时提供了一个便捷的方式来操作 JSON 数据的格式化。这种方式非常适合在需要频繁处理 JSON 数据的项目中,可以显著提升性能和资源利用率。

示例二

“需求:通过单例模式可以确保配置信息在整个系统中只有一个实例,避免多次加载配置文件或多次访问数据库”

实现:

创建配置信息类:这个类负责加载和存储配置信息

// ConfigManager.java - 单例模式的配置管理器
// ConfigManager 类可以进一步扩展,例如支持从文件中加载配置、支持动态更新配置、支持不同环境的配置切换等。这样,通过单例模式管理配置信息,能够有效地避免多次加载配置文件或访问数据库,提高系统性能和管理便捷性。public class ConfigManager {private static ConfigManager instance;
//静态单例实例变量,使用 private static 关键字声明了一个静态的 instance 变量,用于保存 ConfigManager 类的唯一实例。private String configFile; // 用于存储配置文件名或配置内容// 私有构造方法,防止外部实例化private ConfigManager() {// 加载配置文件或初始化配置内容this.configFile = "config.properties"; // 示例配置文件名// 实际应用中可以在构造方法中进行配置文件的加载// 例如:this.loadConfig();}// 公有静态方法,获取唯一实例,getInstance() 方法是获取 ConfigManager 类的实例的唯一入口。这个方法使用了双重检查锁定(double-checked locking)来确保在多线程环境下也能保持单例的唯一性和线程安全性。public static ConfigManager getInstance() {if (instance == null) {synchronized (ConfigManager.class) {if (instance == null) {instance = new ConfigManager();}}}return instance;}// 示例方法:获取配置信息public String getConfig() {return this.configFile;}// 示例方法:设置配置信息public void setConfig(String configFile) {this.configFile = configFile;}
}

 实现单例模式:确保在整个应用中只有一个配置信息实例。

public class MyApp {public static void main(String[] args) {ConfigManager configManager = ConfigManager.getInstance();// 获取配置信息示例String configFile = configManager.getConfig();System.out.println("Current config file: " + configFile);// 修改配置信息示例configManager.setConfig("new_config.properties");System.out.println("Updated config file: " + configManager.getConfig());}
}

        整个 ConfigManager 类符合单例模式的要求:它保证了在整个应用程序中只有一个实例存在,并提供了全局访问点来获取这个唯一的实例。这样做可以确保配置信息在整个系统中只有一个实例,避免了多次加载配置文件或多次访问数据库的问题。 

四、懒汉与饿汉

一文搞懂设计模式—单例模式

在选择单例模式的创建方式时,通常可以选择懒汉模式或饿汉模式,具体取决于项目的需求和使用场景。让我们来比较一下懒汉模式和饿汉模式的特点和适用场景:

饿汉模式

在饿汉模式下,实例在类加载时就被创建,因此称为“饿汉”——因为它一开始就“吃饱了”。

特点

  • 线程安全:由于实例在类加载时就创建并初始化,所以不存在多线程环境下的线程安全问题。
  • 简单:实现起来比较简单,没有复杂的同步控制。
  • 性能较好:在访问量较大或者对性能有一定要求的场景下,由于不需要在获取实例时进行同步操作,性能较好。

适用场景

  • 当单例对象的创建和初始化操作比较简单,且在程序运行时就需要频繁使用时,可以考虑使用饿汉模式。
public class Singleton {private static final Singleton instance = new Singleton();private Singleton() {// 私有构造方法}public static Singleton getInstance() {return instance;}
}

懒汉模式

在懒汉模式下,实例在第一次使用时才进行创建,因此称为“懒汉”——直到需要才“吃”。

特点

  • 延迟加载:只有在首次调用 getInstance() 方法时才会创建实例。
  • 线程安全性需要考虑:如果不加同步控制,在多线程环境下可能会创建多个实例。
  • 资源利用率高:只有在需要时才会创建对象,节省了资源。

适用场景

  • 当单例对象的创建和初始化操作较为复杂或者需要延迟加载时,可以考虑使用懒汉模式。
  • 如果应用中频繁使用单例对象的情况不多,懒汉模式可以节省资源。

示例(带双重检查锁定的懒汉模式):

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;}
}

五、总结

  • 饿汉模式适合在单例对象比较简单,且在程序整个生命周期内需要频繁使用的情况下,可以提升性能。
  • 懒汉模式适合在单例对象创建和初始化较为复杂,或者需要延迟加载的情况下,以节省资源并避免不必要的初始化。

        具体如何选择呢,像示例一中的代码,使用懒汉模式(带双重检查锁定)是比较合适的选择。因为:

  1. 延迟加载:你的 JsonFormatter 类中的 ObjectMapper 实例需要在第一次调用 getInstance() 方法时才被初始化。这种延迟加载的方式可以节省资源,特别是在应用程序启动时,可能不立即需要操作 JSON 的情况下。

  2. 线程安全性:通过双重检查锁定,确保了在多线程环境下只会创建一个 JsonFormatter 实例。这种方式在保证线程安全的同时,又能避免每次调用 getInstance() 都进行同步,提高了性能。

  3. 资源利用:由于 ObjectMapper 可能比较重量级(尤其是在配置了特定的序列化/反序列化规则时),懒汉模式可以避免不必要的对象创建和初始化,从而提高了资源的利用率。

六、说明

日志管理上使用@Slf4j 中的log 这个注解里面没有用到单例模式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/386283.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring之Spring Bean的生命周期

Spring Bean的生命周期 通过BeanDefinition获取bean的定义信息调用构造函数实例化beanBean的依赖注入处理Aware接口(BeanNameAware、BeanFactoryAware、ApplicationContextAware)Bean的后置处理器BeanPostProcessor-前置初始化方法(Initiali…

关于@JsonSerialize序列化与@JsonDeserialize反序列化注解的使用(密码加密与解密举例)

注:另一种方式参考 关于TableField中TypeHandler属性,自定义的类型处理器的使用(密码加密与解密举例)http://t.csdnimg.cn/NZy4G 1.简介 1.1 序列化与反序列化 学习注解之前,我们可以先了解一下什么是序列化与反序列…

115. 不同的子序列 dp入门(一)详细推导dp转移方程式

目录 1. 题目引入: 2. 动态规划解法 2.1 动态dp表示 2.2 动态方程推导: 2.3 具体分析 2.4 初始化 3. 代码如下 java版 c版 Python版 1. 题目引入: 给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果…

计算机基础(day1)

1.什么是内存泄漏?什么是内存溢出?二者有什么区别? 2.了解的操作系统有哪些? Windows,Unix,Linux,Mac 3. 什么是局域网,广域网? 4.10M 兆宽带是什么意思?理论…

OAK-FFC 分体式相机使用入门介绍

概述 OAK FFC 主控板和多种可选配镜头模组非常适合灵活的搭建您的3D人工智能产品原型。由于镜头是分体式的,因此你可以根据需要测量的距离,自定义深度相机安装基线,并根据你的项目要求(分辨率、快门类型、FPS、光学元件&#xff…

项目风险管理:从理论到实践的探索

项目风险管理:从理论到实践的探索 前言一、项目风险识别二、项目风险应对策略三、综合应对策略结语 前言 在当今快速变化的商业环境中,项目管理已成为组织实现目标的关键工具。然而,项目的成功往往伴随着各种不确定性和潜在风险。有效的风险管…

【Git-驯化】一文搞懂git中rm命令的使用技巧

【Git-驯化】一文搞懂git中rm命令的使用技巧 本次修炼方法请往下查看 🌈 欢迎莅临我的个人主页 👈这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合,智慧小天地! 🎇 免费获取相关内容文档关注:微信公…

五、Spring Boot - 上手篇(1)

🌻🌻目录 一、快速入门:创建第一个SpringBoot 工程1.1 点击File--->New--->Project...1.2 选择版本和依赖的相关骨架包1.3 设置项目保存目录1.4 项目创建完成,工程主界面如下1.5 项目说明1.6 启动项目1.7 编写 HelloControl…

快速上手,spring boot3整合task实现定时任务

在已经上线的项目中,定时任务是必不可少的。基于spring boot自动装配的原理,我们要集成task定时任务还是非常简单的。只需要简单的两步就可以实现。 1、创建一个spring boot项目,并在项目的启动类(也不一定非要是启动类&#xff…

如何排查GD32 MCU复位是由哪个复位源导致的?

上期为大家讲解了GD32 MCU复位包括电源复位和系统复位,其中系统复位还包括独立看门狗复位、内核软复位、窗口看门狗复位等,在一个GD32系统中,如果莫名其妙产生了MCU复位,如何排查具体是由哪个复位源导致的呢? GD32 MC…

【RabbitMQ】MQ相关概念

一、MQ的基本概念 定义:MQ全称为Message Queue,是一种提供消息队列服务的中间件,也称为消息中间件。它允许应用程序通过读写队列中的消息来进行通信,而无需建立直接的连接。作用:主要用于分布式系统之间的通信&#x…

vulntarget-b

实际部署之后centos7 的ip有所变动分别是 :192.168.127.130以及10.0.20.30 Centos7 老规矩还是先用fscan扫一下服务和端口,找漏洞打 直接爆出来一个SSH弱口令…,上来就不用打了,什么意思??? 直接xshell…

STM32--HAL库--定时器篇

一:如何配置定时器 打开对应工程串口配置好的工程(上一篇博客)做如下配置: 定时器的中断溢出时间计算公式是: 由图得T100*1000/100MHz 注:100MHz100000000 所以溢出时间等于1ms 关于上图4的自动重装…

【网络安全】文件上传黑白名单及数组绕过技巧

不安全的文件上传(Unsafe FileUpload) 不安全的文件上传是指Web应用程序在处理用户上传的文件时,没有采取足够的安全措施,导致攻击者可能利用这些漏洞上传恶意文件,进而对服务器或用户造成危害。 目录 一、文件上传…

Unity横板动作游戏 - 素材导入和整理

导入素材 编辑器布局 点击每个窗口右上角的三个点可以有更多的窗口选项。 在屏幕的右上角有一个菜单可以保存布局或读取已经报错的布局。 工具按钮 编辑器上的工具按钮在启动的时候是蓝色的,在不启动的时候是灰色的。 这个按钮将会决定场景中的物体是以锚点显示还…

Oracle配置TCPS加密协议测试

文章目录 一、环境信息二、配置过程1.创建证书2.监听配置2.1.配置sqlnet.ora2.2.配置listener.ora文件2.3.配置tnsnames.ora文件2.4.重载监听 3.数据库本地测试3.1. tcps登录测试3.2.日志监控 一、环境信息 操作系统:Linux 版本信息:Oracle 19c 参考文档…

EXCEL自动公式计算始终为0

如果你的数据单元格的左上角存在绿色的三角小箭头,那么就会造成这种问题: 你的数字是以文本形式存入的单元格 解决办法: 选中数据列,数据->分列 直接选择完成 此时就可以进行公式计算了

pytest结合allure-pytest插件生成测试报告

目录 一、安装allure-pytest插件 二、下载allure 三、生成allure报告 四、效果展示 一、安装allure-pytest插件 二、下载allure 下载之后解压,解压之后还要配置环境变量(把allure目录下bin目录配置到系统变量的path路径),下…

企业化运维(8)Docker容器技术

###1.Docker介绍### 什么是Docker Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间…

2024后端开发面试题总结

一、前言 上一篇离职贴发布之后仿佛登上了热门,就连曾经阿里的师兄都看到了我的分享,这波流量真是受宠若惊! 回到正题,文章火之后,一些同学急切想要让我分享一下面试内容,回忆了几个晚上顺便总结一下&#…