一、单例模式
文章目录
- 1 基本介绍
- 2 实现方式
- 2.1 饿汉式
- 2.1.1 代码
- 2.1.2 特性
- 2.2 懒汉式 ( 线程不安全 )
- 2.2.1 代码
- 2.2.2 特性
- 2.3 懒汉式 ( 线程安全 )
- 2.3.1 代码
- 2.3.2 特性
- 2.4 双重检查
- 2.4.1 代码
- 2.4.2 特性
- 2.5 静态内部类
- 2.5.1 代码
- 2.5.2 特性
- 2.6 枚举
- 2.6.1 代码
- 2.6.2 特性
- 3 实现的要点
- 4 线程不安全的单例模式
- 4.1 代码
- 4.2 评价
- 5 JDK中的单例模式
- 6 单例模式的类图及角色
- 6.1 类图
- 6.2 角色
- 7 推荐的单例模式的实现
- 8 单例模式的使用场景
1 基本介绍
单例模式(Singleton Pattern)是一种 创建型 设计模式,其目的是 确保一个类仅有一个实例,并提供一个 静态方法 来获取该实例。
2 实现方式
单例模式围绕着两个特性展开:
- 延迟加载:在需要这个单例时才创建单例,避免浪费内存。
- 线程安全:在多线程环境下,保证多线程使用的单例是同一个单例。
共有以下六种实现方式:
2.1 饿汉式
2.1.1 代码
饿汉式的实现在 Java 中有两种实现,常用的是第一种。
方式一:显式初始化。
public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {}public static synchronized Singleton getInstance() {return INSTANCE;}
}
方式二:静态代码块初始化。
public class Singleton {private static final Singleton INSTANCE;static {INSTANCE = new Singleton();}private Singleton() {}public static synchronized Singleton getInstance() {return INSTANCE;}
}
2.1.2 特性
- 不延迟加载:在 类加载 时就创建单例。
- 线程安全:类加载由 JVM 保证线程安全,所以此时创建的单例也是线程安全的。
2.2 懒汉式 ( 线程不安全 )
2.2.1 代码
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
2.2.2 特性
- 延迟加载:只有在 调用获取单例的方法
getInstance()
时才创建单例。 - 线程不安全:如果有多个线程同时通过了
singleton == null
这个条件,则它们会创建多个单例。
2.3 懒汉式 ( 线程安全 )
2.3.1 代码
注意 getInstance()
方法前的 synchronized
修饰符。
public class Singleton {private static Singleton instance;private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}
2.3.2 特性
- 延迟加载:只有在 调用获取单例的方法
getInstance()
时才创建单例。 - 线程安全:在多个线程同时获取单例时,使用
synchronized
互斥锁,来保证只有一个线程能够生成单例,而其他线程等待这个线程创建的单例,保证了单例的线程安全。 - 成本太大:即使已经有单例了,每次调用
getInstance()
方法还得经过 加锁 和 释放锁 的流程(因为使用了synchronized
互斥锁),降低了并发性能。
2.4 双重检查
2.4.1 代码
注意单例前的 volatile
修饰符,它有两个作用:保证变量对所有线程可见 和 防止指令重排。在此处起 防止指令重排 的作用:防止 JIT 即时编译器对 instance = new Singleton();
这行代码进行重排序。
如果进行重排序,则可能先给 instance
分配内存(此时 instance != null
),然后才调用构造器为 instance
的属性赋值。在这两步操作之间,要是有线程调用 getInstance()
方法,它将无法通过外层的 instance == null
条件,会返回一个不完整(赋值不完全)的对象。
public class Singleton {private static volatile Singleton instance; // 注意 volatile 在这里起 防止指令重排 的作用private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}
2.4.2 特性
- 延迟加载:只有在 调用获取单例的方法
getInstance()
时才创建单例。 - 线程安全:在多个线程同时获取单例 且 单例未创建时,如果都通过了外层的
instance == null
条件,则在内层使用synchronized
互斥锁,来保证只有一个线程创建单例,而其他线程等待这个线程创建的单例,保证了单例的线程安全。 - 成本小:这种实现方式只有最初创建单例时会加互斥锁,之后就不需要创建单例了,直接返回即可,无需加锁和释放锁,提高了并发性能。
2.5 静态内部类
2.5.1 代码
public class Singleton {private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}public static Singleton getInstance() {return SingletonHolder.INSTANCE;}
}
2.5.2 特性
- 延迟加载:只有在 调用获取单例的方法
getInstance()
时,才会 触发静态内部类的加载,从而创建单例。 - 线程安全:静态内部类也是类,类加载由 JVM 保证其线程安全,所以本单例是线程安全的。
2.6 枚举
2.6.1 代码
public enum Singleton {INSTANCE; // 直接使用 Singleton.INSTANCE 就可以获取到单例// 可以随意写方法和属性,就像在类中一样
}
2.6.2 特性
- 不延迟加载:在 类加载 时就创建单例。
- 线程安全:类加载由 JVM 保证线程安全,所以此时创建的单例也是线程安全的。
- 防止 反射 或 反序列化 破坏单例:其他单例的实现都可以通过 反射 或 反序列化 的方式重新创建新的单例,唯独本实现无法使用这两种方式重新创建新的单例,这是因为 枚举无法通过反射获取对象,并且 枚举在序列化和反序列化时不会调用构造器。所以这种实现是 最推荐的。
3 实现的要点
- 构造器私有化。例如
private Singleton() {}
。 - 类中有一个 静态 的单例属性。
- 提供一个 静态 方法来获取上述单例。
4 线程不安全的单例模式
4.1 代码
public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {instance = new Singleton();}}return instance;}
}
4.2 评价
这样的单例模式是 线程不安全 的,synchronized
互斥锁没有起到应有的作用。只要多个线程都能通过 instance == null
条件,则它们每个线程都会创建一次单例,synchronized
仅仅能保证同一时刻只有一个线程在创建单例罢了。
应该将 判断 和 赋值 都放到 synchronized
互斥锁里,就像单例的 第三种实现——懒汉式 ( 线程安全 ) 一样。
5 JDK中的单例模式
在JDK中,Runtime
类使用了 饿汉式单例,代码如下:
public class Runtime {private static final Runtime currentRuntime = new Runtime();public static Runtime getRuntime() {return currentRuntime;}private Runtime() {}// ...
}
6 单例模式的类图及角色
6.1 类图
其中,singleton
属性和 Singleton()
构造器都是 私有的,而 getInstance()
方法是 公开的。此外,singleton
属性和 getInstance()
方法都是 静态的。
6.2 角色
在单例模式中,只有一个角色 Singleton
,它负责 实现返回单例的 静态 方法。
7 推荐的单例模式的实现
- 饿汉式
- 双重检查
- 静态内部类
- 枚举
8 单例模式的使用场景
- 创建对象耗时过多或耗费资源过多(重量级),但经常用到。
- 频繁访问 数据库 或 文件 的对象。
- 工具类对象。
相关文章:

一、单例模式
文章目录 1 基本介绍2 实现方式2.1 饿汉式2.1.1 代码2.1.2 特性 2.2 懒汉式 ( 线程不安全 )2.2.1 代码2.2.2 特性 2.3 懒汉式 ( 线程安全 )2.3.1 代码2.3.2 特性 2.4 双重检查2.4.1 代码2.4.2 特性 2.5 静态内部类2.5.1 代码2.5.2 特性 2.6 枚举2.6.1 代码2.6.2 特性 3 实现的要…...
B树:高效的数据存储结构
在计算机科学中,B树(B-Tree)是一种平衡多路查找树,它广泛应用于数据库和文件系统等需要高效数据存储和检索的场景。B树的设计旨在优化磁盘I/O操作,通过减少磁盘访问次数来提高数据检索的效率。本文将介绍B树的基本概念…...

[Vulnhub] TORMENT IRC+FTP+CUPS+SMTP+apache配置文件权限提升+pkexec权限提升
信息收集 IP AddressOpening Ports192.168.101.152TCP:21,22,25,80,111,139,143,445,631 $ nmap -p- 192.168.101.152 --min-rate 1000 -sC -sV PORT STATE SERVICE VERSION 21/tcp open ftp vsftpd 2.0.8 or later | ftp-anon: Anonymous FTP login a…...

<数据集>安全帽佩戴识别数据集<目标检测>
数据集格式:VOCYOLO格式 图片数量:3912张 图片分辨率:640640 标注数量(xml文件个数):3912 标注数量(txt文件个数):3912 标注类别数:2 标注类别名称:[no-helmet, helmet] 序号类别名称图片…...

[米联客-安路飞龙DR1-FPSOC] FPGA基础篇连载-21 VTC视频时序控制器设计
软件版本:Anlogic -TD5.9.1-DR1_ES1.1 操作系统:WIN10 64bit 硬件平台:适用安路(Anlogic)FPGA 实验平台:米联客-MLK-L1-CZ06-DR1M90G开发板 板卡获取平台:https://milianke.tmall.com/ 登录“米联客”FPGA社区 ht…...

记录uni-app横屏项目:自定义弹出框
目录 前言: 正文: 前言:横屏的尺寸问题 最近使用了uniapp写了一个横屏的微信小程序和H5的项目,也是本人首次写的横屏项目,多少是有点踩坑不太适应。。。 先说最让我一脸懵的点,尺寸大小,下面一…...
Linux Vim教程(二):基本命令和操作
目录 1. 进入和退出Vim 1.1 启动Vim 1.2 退出Vim 2. 模式切换 2.1 切换到插入模式 2.2 切换到普通模式 2.3 切换到命令模式 2.4 切换到可视模式 3. 移动光标 4. 编辑文本 4.1 插入和追加文本 4.2 删除文本 4.3 复制和粘贴文本 4.4 撤销和重做 5. 搜索和替换 5.…...
【大模型基础】4.1 数据挖掘(待)
一、什么是文本挖掘? 文本挖掘指的是从文本数据中获取有价值的信息和知识,它是数据挖掘中的一种方法。文本挖掘中最重要最基本的应用是实现文本的分类和聚类,前者是有监督的挖掘算法,后者是无监督的挖掘算法。 二、文本挖掘的作用是什么? 能够从文本数据中获取有价值的…...
Jupyter Notebook与机器学习:使用Scikit-Learn构建模型
Jupyter Notebook与机器学习:使用Scikit-Learn构建模型 介绍 Jupyter Notebook是一款强大的交互式开发环境,广泛应用于数据科学和机器学习领域。Scikit-Learn是一个流行的Python机器学习库,提供了简单高效的工具用于数据挖掘和数据分析。本…...

IMU提升相机清晰度
近期,一项来自北京理工大学和北京师范大学的团队公布了一项创新性的研究成果,他们将惯性测量单元(IMU)和图像处理算法相结合,显著提升了非均匀相机抖动下图像去模糊的准确性。 研究团队利用IMU捕捉相机的运动数据&…...
掌握SQL Server性能监控:自定义性能计数器的实现
掌握SQL Server性能监控:自定义性能计数器的实现 在数据库管理中,监控数据库性能是确保系统稳定运行的关键。SQL Server提供了丰富的性能监控工具,但有时这些工具可能无法满足特定的监控需求。这时,自定义性能计数器就显得尤为重…...

jdk1.8 List集合Stream流式处理
jdk1.8 List集合Stream流式处理 一、介绍(为什么需要流Stream,能解决什么问题?)1.1 什么是 Stream?1.2 常见的创建Stream方法1.3 常见的中间操作1.4 常见的终端操作 二、创建流Stream2.1 Collection的.stream()方法2.2 数组创建流2.3 静态工厂…...
leetcode位运算(1720. 解码异或后的数组)
前言 经过前期的基础训练以及部分实战练习,粗略掌握了各种题型的解题思路。后续开始专项练习。 描述 未知 整数数组 arr 由 n 个非负整数组成。 经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] arr[i] XOR arr[i 1] 。例如&am…...

Android 性能优化之卡顿优化
文章目录 Android 性能优化之卡顿优化卡顿检测TraceView配置缺点 StricktMode配置违规代码 BlockCanary配置问题代码缺点 ANRANR原因ANRWatchDog监测解决方案 Android 性能优化之卡顿优化 卡顿检测 TraceViewStricktModelBlockCanary TraceView 配置 Debug.startMethodTra…...
mac电脑显示隐藏文件
方法一: 第一步:打开「终端」应用程序。 第二步:输入如下命令: defaults write com.apple.finder AppleShowAllFiles -boolean true ; killall Finder 第三步:按下「Return」键确认。 现在你将会在 Finder 窗口中…...

深度学习之基础知识整理
现在大语言模型很火,但它的基础仍然是以神经网络为基础的深度学习,不懂神经网络,不了解深度学习,对于大语言模型的二次开发也是整不明白。 那到底需要了解哪些知识?才能看懂深度学习/神经网络的基础模型,想…...
R语言学习笔记9-数据过滤-分组-融合
R语言学习笔记9-数据过滤-分组-融合 数据过滤基础数据过滤条件筛选数据使用dplyr包进行数据操作select 函数filter 函数subset函数 数据分组使用split()进行数据分组使用dplyr包进行数据分组使用data.table包进行数据分组 数据融合使用merge()进行数据融合使用dplyr包进行数据融…...
GESP CCF C++ 八级认证真题 2024年6月
第 1 题 GESP活动期间,举办方从获胜者ABCDE五个人中选出三个人排成一队升国旗,其中A不能排在队首,请问 有多少种排法? A.24 B.48 C.32 D.12 第 2 题 7进制数235转换成3进制数是( )。 A. 11121 B. 11…...
Spring Boot 单元测试什么时候需要添加 @RunWith
建立 Spring Boot 单元测试方法一般依赖于 JUnit4 或 JUnit5 框架。 在高版本的 Spring Boot 中,一般默认用的是 JUnit5。此时通过添加 SpringBootTest 注解,即可成功注入相关的 bean 对象,并进行测试。 import org.junit.jupiter.api.Test…...

鸿蒙OpenHarmony Native API【HiLog】
HiLog Overview Description: HiLog模块实现日志打印功能。 开发者可以通过使用这些接口实现日志相关功能,输出日志时可以指定日志类型、所属业务领域、日志TAG标识、日志级别等。 syscap SystemCapability.HiviewDFX.HiLog Since: 8 Summary Files File …...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...