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

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

单例模式的分类

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

  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.mzph.cn/news/15936.shtml

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

相关文章

Mac 终端快捷键设置:如何给 Mac 中的 Terminal 设置 Ctrl+Alt+T 快捷键快速启动

Mac 电脑中正常是没有直接打开终端命令行的快捷键指令的&#xff0c;但可以通过 commandspace 打开聚焦搜索&#xff0c;然后输入 ter 或者 terminal 全拼打开。但习惯了 linux 的同学会觉得这个操作很别扭。于是我们希望能通过键盘按键直接打开。 操作流程如下&#xff1a; 1…

Docker 安全及日志管理

目录 前言&#xff1a; 一&#xff1a;Docker 容器与虚拟机的区别 1. 隔离与共享 2. 性能与损耗 二&#xff1a;Docker 存在的安全问题 1.Docker 自身漏洞 2.Docker 源码问题 三&#xff1a;Docker 架构缺陷与安全机制 1. 容器之间的局域网攻击 2. DDoS 攻击耗尽资…

《MapboxGL 基础知识点》- 地图监听事件

添加地图监听事件 使用方法 map.on map.on(type, layerIds, listener) 例如 map.on(mouseup, onMouseup);function onMouseup(e) {// mouseupconsole.log(e.type); } 取消地图监听事件 使用方法 map.off map.off(type, layerIds, listener) 例如&#xff1a; map.off(…

MyBatis小记_one

目录 什么是框架 1.框架的概述 2.框架要解决的问题 3. 软件开发的分层重要性 4.分层开发的常见框架 MyBatis 框架概述 JDBC 编程的回顾 JDBC 问题分析 MyBatis 框架快速入门 1.官网下载MyBatis框架jar包 2.搭建MyBatis 开发环境 3. 编写持久层接口的映射文件 IUserD…

HTML笔记(1)

介绍 浏览器中内置了HTML的解析引擎&#xff0c;通过解析标记语言来展现网页&#xff1b;HTML标签都是预定义好的&#xff1b;Java工程师&#xff1a;后台代码的编写&#xff0c;和数据库打交道&#xff0c;把数据给网页前端的工程师&#xff1b;网页前端工程师&#xff1a;写H…

C++信号量与共享内存实现进程间通信

关于信号量和共享内存的相关知识可参考下面链接&#xff1a; 进程间通信方式介绍_夜雨听萧瑟的博客-CSDN博客 C 创建共享内存_c共享内存_夜雨听萧瑟的博客-CSDN博客 信号量SytemV与Posix信号量的介绍与用法_夜雨听萧瑟的博客-CSDN博客 直接上代码&#xff0c;代码如下&#…

记一次Apache HTTP Client问题排查

现象 通过日志查看&#xff0c;存在两种异常情况。第一种&#xff1a;开始的时候HTTP请求会报超时异常。 762663363 [2023-07-21 06:04:25] [executor-64] ERROR - com.xxl.CucmTool - CucmTool|sendRisPortSoap error,url:https://xxxxxx/realtimeservice/services/RisPort o…

【C语言】通讯录2.0 (动态增长版)

前言 通讯录是一种记录联系人信息的工具&#xff0c;包括姓名、电话号码、电子邮件地址、住址等。 文章的一二三章均于上一篇相同&#xff0c;可以直接看第四章改造内容。 此通讯录是基于通讯录1.0&#xff08;静态版&#xff09;的基础上进行改进&#xff0c;请先看系列文字第…

自动化测试:让软件测试更高效更愉快!

谈谈那些实习测试工程师应该掌握的基础知识&#xff08;一&#xff09;_什么时候才能变强的博客-CSDN博客https://blog.csdn.net/qq_17496235/article/details/131839453谈谈那些实习测试工程师应该掌握的基础知识&#xff08;二&#xff09;_什么时候才能变强的博客-CSDN博客h…

css 动画之旋转视差

序&#xff1a;网上看到的一个例子&#xff0c;做一下 效果图&#xff1a; 代码&#xff1a; <style>.content{width: 300px;height: 300px;margin: 139px auto;display: grid;grid-template-columns: repeat(3,1fr);grid-template-rows: repeat(3,1fr);grid-template:…

Python 进阶(六):文件读写(I/O)

❤️ 博客主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;Python 入门核心技术 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; 文章目录 1. 打开文件2. 读取文件2.1 逐行读取文件2.2 读取所有行 3. 写入文件3.1 向文件中写入…

从0到1开发go-tcp框架【1-搭建server、封装连接与业务绑定、实现基础Router、抽取全局配置文件】

从0到1开发go-tcp框架【1-搭建server、封装连接与业务绑定、实现基础Router】 本期主要完成对Server的搭建、封装连接与业务绑定、实现基础Router&#xff08;处理业务的部分&#xff09;、抽取框架的全局配置文件 从配置文件中读取数据&#xff08;服务器监听端口、监听IP等&a…

在CSDN学Golang云原生(Kubernetes集群安全)

一&#xff0c;ABAC授权模式 Kubernetes ABAC&#xff08;Attribute-Based Access Control&#xff09;授权模式是一种基于属性的访问控制模型&#xff0c;它可以根据用户或组的属性决定是否允许他们访问 Kubernetes 集群中的资源。 在使用 ABAC 授权模式时&#xff0c;管理员…

汇编语言基础知识

目录 前言&#xff1a; 汇编语言的产生 汇编语言的组成 内存 指令和数据 cpu对内存的读写操作 地址总线 数据总线 控制总线 内存地址空间 前言&#xff1a; 汇编语言是直接在硬件之上工作的 编程语言&#xff0c;我们首先了解硬件系统的机构&#xff0c;才能有效地应用…

C/C++多线程操作

文章目录 多线程C创建线程join 和detachthis_thread线程操作锁lock_guardunique_lock 条件变量 condition_variablewaitwaitfor C语言线程创建线程同步 参考 多线程 传统的C&#xff08;C11标准之前&#xff09;中并没有引入线程这个概念&#xff0c;在C11出来之前&#xff0c…

PyTorch Lightning教程四:超参数的使用

如果需要和命令行接口进行交互&#xff0c;可以使用Python中的argparse包&#xff0c;快捷方便&#xff0c;对于Lightning而言&#xff0c;可以利用它&#xff0c;在命令行窗口中&#xff0c;直接配置超参数等操作&#xff0c;但也可以使用LightningCLI的方法&#xff0c;更加轻…

WPF实战学习笔记22-添加自定义询问窗口

添加自定义询问窗口 详细代码&#xff1a;https://github.com/DongLiqiang/Mytodo/commit/221de6b2344d5c861f1d3b2fbb2480e3e3b35c26 添加自定义询问窗口显示方法 修改文件Mytodo.Extensions.DialogExtension 添加内容&#xff0c;类中添加内容 /// <summary> /// …

【编译】gcc make cmake Makefile CMakeList.txt 区别

文章目录 一 关系二 gcc2.1 编译过程2.2 编译参数2.3 静态库和动态库1 后缀名2 联系与区别 2.4 GDB 调试器1 常用命令 三 make、makefile四 cmake、cmakelist4.1 语法特性4.2 重要命令4.2 重要变量4.3 编译流程4.4 两种构建方式 五 Vscode5.0 常用快捷键5.1 界面5.2 插件5.3 .v…

使用 docker 一键部署 MySQL

目录 1. 前期准备 2. 导入镜像 3. 创建部署脚本文件 4. MySQL 服务器配置文件模板 5. 执行脚本创建容器 6. 后续工作 7. 基本维护 1. 前期准备 新部署前可以从仓库&#xff08;repository&#xff09;下载 MySQL 镜像&#xff0c;或者从已有部署中的镜像生成文件&#x…

Shell错误:/bin/bash^M: bad interpreter: No such file or directory

目录 错误原因和现象 解决方案 错误原因和现象 在执行shell脚本的时候&#xff0c;报错&#xff1a;/bin/bash^M: bad interpreter: No such file or directory。 是由于该脚本文件是在Windows平台编写&#xff0c;然后在MacOS平台中执行。 在Windows平台上文件是dos格式&…