设计模式四:单例模式(Singleton)

news/2024/5/17 16:57:40

单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。
通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
单例模式是设计模式中最简单的形式之一。这一模式的目的是使得类的一个对象成为系统中的唯一实例。
要实现这一点,可以从客户端对其进行实例化开始。因此需要用一种只允许生成对象类的唯一实例的机制,“阻止”所有想要生成对象的访问。

单例模式的分类

单例模式可以根据实现方式的不同,分为以下几种分类:

  1. 饿汉式(Eager Initialization):在类加载的时候就创建并初始化单例对象。这种方式简单直接,线程安全,但可能会造成资源浪费,因为即使没有使用单例对象,它也会被提前创建。
  2. 懒汉式(Lazy Initialization):在第一次使用时创建单例对象。这种方式避免了不必要的资源浪费,但需要考虑线程安全性,确保在多线程环境下仍然能够正确地创建单例对象。
  3. 双重检验锁(Double-Checked Locking):结合了懒汉式和饿汉式的优点,在多线程环境下既能保证线程安全,又能延迟单例对象的创建。这种方式通过加锁来控制并发访问,并使用 volatile 关键字来保证可见性。
  4. 静态内部类(Static Inner Class):利用类加载机制来实现延迟加载和线程安全的单例对象。通过定义一个私有的静态内部类,在这个静态内部类中创建单例对象,从而保证只有在第一次使用时才会触发单例对象的初始化。
  5. 枚举(Enum):枚举类型本身就是单例的。在Java中,枚举类型能够保证在任何情况下都只有一个实例。因此,可以直接使用枚举来实现单例模式。
    这些分类方式基本上涵盖了常见的单例模式实现方式。根据具体的需求和场景,选择适合的单例模式实现方式可以提高代码的可靠性和性能效率。

Singleton模式的使用场景

单例模式是一种常见的设计模式,在以下情况下可以考虑使用单例模式:
1.全局资源共享:当应用程序需要在多个部分共享同一个资源时,可以使用单例模式确保只有一个实例存在。例如,数据库连接池、日志记录器等全局资源可以使用单例模式来管理和访问。
2.对象缓存:当需要缓存对象以提高性能时,可以使用单例模式来管理缓存。通过保持单例实例,可以避免重复创建对象,并且在需要时可以快速获取缓存对象。
3.配置信息管理:当应用程序需要维护一些全局配置信息时,可以使用单例模式来管理这些配置。这样可以确保只有一个实例保存和管理配置信息,并且可以在程序的各个地方使用。
4.日志记录器:在应用程序中,通常需要一个日志记录器来记录系统的操作和异常信息。通过使用单例模式,可以方便地在代码的任何地方访问和使用统一的日志记录器。
5.系统计数器:某些场景需要记录系统某些操作的次数,如请求处理次数、任务处理次数等。使用单例模式可以方便地实现对统计数据的更新和访问。
需要注意的是,单例模式并不适用于所有的场景。在一些情况下,它可能会导致代码的复杂性增加,或者造成不必要的性能开销。

饿汉式

指全局的单例实例在类装载时构建。它是线程安全的,但是如果这个类我一直不使用,由于类初始化时,就已经实例它了,所以它会一直占着资源不释放。

/*** 单例模式*/
public class Singleton {// 饿汉式private static Singleton instance2 = new Singleton();public static Singleton getInstance3(){return instance2;}
}

懒汉式–线程不安全

最基础的实现方式,线程上下文单例,不需要共享给所有线程,也不需要加synchronize之类的锁,以提高性能,有个致命缺点,就是在两个相同的线程中同时调用了getInstance1() 时,就会在这两个线程中产生不同的Singleton 对象。单例的作用就相当没有了。由于它的线程不安全,所以有了下面的方式。

/*** 单例模式*/
public class Singleton {private static Singleton instance;// 懒汉式—线程不安全public static Singleton getInstance1(){if (instance == null){instance = new Singleton();}return instance;}
}

懒汉式–线程安全

加上synchronize之类保证线程安全的基础上的懒汉模式,相对性能很低,大部分时间并不需要同步。

/*** 单例模式*/
public class Singleton {private static Singleton instance;// 懒汉式—线程安全public static synchronized Singleton getInstance2(){if (instance == null){instance = new Singleton();}return instance;}
}

它是线程安全了;但由于它是同步方法,在多线程调用它时,都会synchronized下,从而效率低下。在使用的过程中为了提高效率,所以我们有了如下方式

双重检验锁

在懒汉式基础上利用synchronize关键字和volatile关键字确保第一次创建时没有线程间竞争而产生多个实例,仅第一次创建时同步,性能相对较高

public class Singleton {private static volatile Singleton instance;private Singleton() {// 私有构造函数,防止外部创建实例}public static synchronized Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}

在上述代码中,getInstance() 方法使用了双重检验锁,首先检查 instance 是否为 null,如果是,则再进入同步块进行二次检查,确保只有一个线程能够创建实例。同时,为了避免由于指令重排序而导致的问题,需要给 instance 声明为 volatile,保证可见性。

静态内部类(登记式)

创建类的全局属性存在,创建类被装载时创建。

public class Singleton {private static Map<String, Singleton> registry = new HashMap<>();private Singleton() {// 私有构造函数,防止外部实例化}public static synchronized Singleton getInstance(String key) {if (!registry.containsKey(key)) {registry.put(key, new Singleton());}return registry.get(key);}
}

第一次记载Singleton 时并不会初始化instance,只有第一次调用getInstance4()时才会实例化。它不仅保证线程安全、也能保证对象的唯一性,同时也延迟了单例的实例化。它也是最为推荐的一种单例模式


http://www.mrgr.cn/p/11147380

相关文章

一文谈谈Git

"And if forever lasts till now Alright" 为什么要有git&#xff1f; 想象一下&#xff0c;现如今你的老师同时叫你和张三&#xff0c;各自写一份下半年的学习计划交给他。 可是你的老师是一个极其"较真"的人&#xff0c;发现你俩写的学习计划太"水&…

MySQL5.7 与 MariaDB10.1 审计插件兼容性验证

这是一篇关于发现 MariaDB 审计插件导致 MySQL 发生 crash 后&#xff0c;展开适配验证并进行故障处理的文章。 作者&#xff1a;官永强 爱可生DBA 团队成员&#xff0c;擅长 MySQL 运维方面的技能。热爱学习新知识&#xff0c;亦是个爱打游戏的宅男。 本文来源&#xff1a;原创…

简单认识redis高可用实现方法

文章目录 一、redis群集三种模式二、 Redis 主从复制1、简介2、作用&#xff1a;3、流程&#xff1a;4.配置主从复制 三、Redis 哨兵模式1、简介2、原理:3、作用&#xff1a;4、哨兵结构由两部分组成&#xff0c;哨兵节点和数据节点&#xff1a;5、故障转移机制&#xff1a;6、…

软件外包开发的后台开发语言

在软件外包开发中&#xff0c;后台语言的选择通常取决于项目需求、客户偏好、团队技能和开发效率。今天和大家分享一些常用的后台语言及选择它们的原因&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。…

【利诱和强制分享下载】规则修改指引

代码审核环节&#xff0c;将会对小程序运营的内容进行核实是否存在阻断功能&#xff0c;损害用户体验。 常见利诱诱导类型&#xff1a; 1、利诱下载APP 小程序内出现不断弹窗、频繁提示诱导用户下载APP&#xff0c;强制用户必须下载APP才能体验完整功能服务。 示例&#xf…

数字化时代,如何做好用户体验与应用性能管理

引言 随着数字化时代的到来&#xff0c;各个行业的应用系统从传统私有化部署逐渐转向公有云、行业云、微服务&#xff0c;这种变迁给运维部门和应用部门均带来了较大的挑战。基于当前企业 IT 运维均为多部门负责&#xff0c;且使用多种运维工具&#xff0c;因此&#xff0c;当…

【Spring】Spring 中事务的实现

事务定义&#xff1a;将⼀组操作封装成⼀个执⾏单元&#xff08;封装到⼀起&#xff09;&#xff0c;要么全部成功&#xff0c;要么全部失败 Spring 中的事务操作分为两类&#xff1a; 编程式事务&#xff08;⼿动写代码操作事务&#xff09;。声明式事务&#xff08;利⽤注解…

【hive】Install hive using mysql as hive metadata service

文章目录 一. Requirements二. Installing Hive from a Stable Release三. Running Hive四. Running Hive CLI五.Running HiveServer2 and Beeline1. 下载安装mysql2. 下载mysql驱动3. 配置hive-site.xml4. 初始化元数据库5. 通过beeline进行连接 一. Requirements Users are s…

php 生成连续递增的Excel列索引 可以控制多少列

今天遇到需要生成对应的下拉&#xff0c;下拉的类 需要PHP 输出一个数组 如 A、B、C、D 到Z 列后 Excel 的列就变成 AA 、AB、 AC 依次类推 查询得知 Excel 最大列数 16384 最大行数 1048576 下面演示3000列或行 <?php$idx [idx > 0];for ($i …

OpenCV4.3 Java 编程入门:透明度与抠图

1. 基础知识 JPG 格式图片有损压缩和不支持半透明&#xff0c;如果想在图片上添加透明通道&#xff0c;一定不要用 JPG 格式的图片&#xff1b;PNG&#xff1a;既支持3通道RGB图像&#xff0c;也支持4通道RGBA图像&#xff08;红色、绿色、蓝色和透明度&#xff09;&#xff1…

NOSQL之Redis配置及优化

目录 一、关系型数据库 二、非关系型数据库 三、关系型数据库和非关系型数据库区别 1、数据存储方式不同 2、扩展方式不同 3、对事务性的支持不同 四、Redis简介 五、Redis优点 &#xff08;1&#xff09;具有极高的数据读写速度 &#xff08;2&#xff09;支持丰富的…

AI 绘画Stable Diffusion 研究(一)sd整合包v4.2 版本安装说明

部署包作者:秋葉aaaki 免责声明: 本安装包及启动器免费提供 无任何盈利目的 大家好&#xff0c;我是风雨无阻。众所周知&#xff0c;StableDiffusion 是非常强大的AI绘图工具&#xff0c;需要详细了解StableDiffusion的朋友&#xff0c;可查看我之前的这篇文章&#xff1a; 最…

9条建议告诉你如何正确处理PCB设计布线

一、关于PCB布线线宽 1、布线首先应满足工厂加工能力&#xff0c;首先向客户确认生产厂家&#xff0c;确认其生产能力&#xff0c;如图1所示。如客户无要求&#xff0c;线宽参考阻抗设计模板。 图1 PCB板厂线宽要求 2、阻抗模板&#xff0c;根据客户提供的板厚及层数要求&…

页面生成图片或PDF node-egg

没有特别的幸运&#xff0c;那么就特别的努力&#xff01;&#xff01;&#xff01; 中间件&#xff1a;页面生成图片 node-egg 涉及到技术node egg Puppeteer 解决文书智能生成多样化先看效果环境准备初始化项目 目录结构核心代码 完整代码https://gitee.com/hammer1010_ad…

[论文笔记] CLRerNet: Improving Confidence of Lane Detection with LaneIoU

Honda, Hiroto, and Yusuke Uchida. “CLRerNet: Improving Confidence of Lane Detection with LaneIoU.” arXiv preprint arXiv:2305.08366 (2023). 2023.05 出的一篇车道线检测的文章, 效果在CULane, CurveLanes SOTA 文章目录 简介LaneIoULineIoU存在问题为什么使用LaneIo…

06. 管理Docker容器数据

目录 1、前言 2、Docker实现数据管理的方式 2.1、数据卷&#xff08;Data Volumes&#xff09; 2.2、数据卷容器&#xff08;Data Volume Containers&#xff09; 3、简单示例 3.1、数据卷示例 3.2、数据卷容器示例 1、前言 在生产环境中使用 Docker&#xff0c;一方面…

记一次sql注入分析与绕过【一】

下面是来自今天的项目&#xff0c;简单记录一下 手工注入 加单引号sql报错 sql语句如下&#xff0c;可见参数id原本未被引号包裹 SELECT DISTINCT u.* FROM t_user u WHERE u.name like %1% and u.account like %1% and u.state ? order by id desc limit 0,20 多方尝试…

回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现GRNN广义回归神经网络多输入单输出回归预测(多指标,多图)效果一览基本介绍程序设计参考资料效果一览 基本介绍 MATLAB实现GRNN广义回归神经网络多输入单输出回归…

Android 面试题 应用程序结构 九

&#x1f525; 核心应用程序 Activity五个状态&#x1f525; Starting-> running-> paused-> stopped-> killed 启动状态&#xff08;Starting&#xff09;&#xff1a;Activity的启动状态很短暂&#xff0c;当Activity启动后便会进入运行状态&#xff08;Running…

HTTP协议+GET/POST区别

1. web开发流程 &#xff08;1&#xff09; HTML、CSS、JS、图片等资源通过浏览器进行整合&#xff0c;最终渲染出所需画面。 &#xff08;2&#xff09;浏览器对Web服务器进行资源请求 浏览器通过url请求资源。【HTTP协议、URL&#xff1a;确定唯一的一个资源】 浏览器请求…