设计模式-单例设计模式
目录
什么是单例设计模式?
为什么要使用单例模式?
资源方面
数据一致方面
系统性能方面
代码维护方面
如何设计单例类?
在说模式之前,我们需要先知道怎么设计才可以让一个类只能有一个实例化对象呢?
饿汉模式
懒汉模式
如何理解懒汉模式的双层判断解决线程安全?
什么是单例设计模式?
单例设计模式是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例;
简单来说就是单例类只能实例化出一个对象;概念不难理解,我们要探讨的就是如何实现单例类,也就是如何控制一个类才能保证只有一个类呢?
为什么要使用单例模式?
资源方面
- 避免资源重复占用:在某些场景下,创建多个相同的对象会造成资源的浪费。比如数据库连接,每次创建数据库连接都需要消耗一定的系统资源,像网络资源、内存资源等。使用单例模式,就能保证整个应用程序中只有一个数据库连接实例,避免了重复创建连接带来的资源浪费,提高了资源的利用效率。
- 控制资源访问:对于一些共享资源,如文件系统、打印机等,单例模式可以对资源的访问进行有效的控制。以文件系统为例,如果多个对象同时对同一个文件进行写操作,可能会导致数据混乱。通过单例模式,可以确保同一时间只有一个对象对文件进行操作,保证了数据的一致性和完整性。
数据一致方面
- 全局数据共享:单例对象可以作为全局数据的存储和访问点,在应用程序的不同模块之间共享数据。例如,在一个游戏应用中,游戏的配置信息(如游戏难度、关卡设置等)可以存储在单例对象中,各个游戏模块都可以通过单例对象来获取和修改这些配置信息,保证了数据的一致性和同步性。
- 状态管理:在一些需要维护全局状态的应用中,单例模式可以很好地管理这些状态。比如,一个在线购物系统中的购物车,使用单例模式可以确保用户在整个购物过程中只有一个购物车实例,无论用户在哪个页面进行商品添加、删除等操作,都是对同一个购物车进行操作,避免了状态不一致的问题。
系统性能方面
- 减少对象创建开销:创建对象需要分配内存、初始化等操作,这些操作会消耗一定的时间和系统资源。单例模式只创建一个对象,避免了多次创建对象的开销,提高了系统的性能。特别是在对象创建成本较高的情况下,如创建数据库连接池、线程池等,单例模式的优势更加明显。
- 提高访问效率:由于单例对象的全局访问点是固定的,访问单例对象的速度比频繁创建和销毁对象要快得多。在需要频繁访问某个对象的场景下,使用单例模式可以显著提高系统的响应速度。
代码维护方面
- 简化代码结构:单例模式将对象的创建和管理逻辑集中在一个类中,使得代码结构更加清晰和简洁。在整个应用程序中,只需要关注单例类的实现和使用,而不需要在各个模块中重复编写对象创建和管理的代码,降低了代码的复杂度,提高了代码的可维护性。
- 便于代码修改和扩展:当需要对单例对象的功能进行修改或扩展时,只需要在单例类中进行修改,而不需要在整个应用程序中查找和修改相关代码。这样可以减少代码修改的工作量,降低引入新错误的风险。
如何设计单例类?
单例分为饿汉模式和懒汉模式
在说模式之前,我们需要先知道怎么设计才可以让一个类只能有一个实例化对象呢?
我们回顾一下之前的创建一个类的方式;
-->调用构造函数对吧,而且是public权限的构造函数;
诶?那我们如果把构造函数设置为私有的了,那么类外这不就无法创建对象了吗,确实是起到了限制对象数量的作用;
但这样我们该如何创建对象呢?
-->类外无法创建那就在类内创建对象!因为单例本就是只有一个对象,该对象会被其他线程共享,数据都是一致的,所以我们只需要维护好这一个类的方法就好了,在哪里创建不关心这个;
我们在类内创建一个对象;
class A
{
private:A() {}
private:A _ins;
public:void f(){cout << "创建一个单例对象" << endl; }
};
但是这里会出现问题,那么就A类还没有构建完毕,是不可以使用A类型作为成员的;
那我们应该如何定义呢?--->静态成员变量;
静态成员变量是比较特殊的成员变量,他处于全局区,每一个类只能实例化出的里面的静态成员都是同一个;
需要注意在类外初始化;正是因为他是在类外实例化的,所以不会和A类同时构造,而是实例化的时间不同;不会出现上述报错;
class A
{
private:A() {}
private:static A _ins;
public:void f(){cout << "创建一个单例对象" << endl; }static A GetA(){return _ins; }
};
所以我们现在已经可以通过类内创建A对象。并且也是可以直接通过域名直接获得,但是为了体现封装性最好使用一个接口;当然这个接口也是要使用static,因为我们要使用域名访问该接口,然后获得单例对象;
饿汉模式
饿汉式在类加载时就立即创建单例对象,不管这个对象是否马上会被使用。就好像一个 “饥饿” 的人,迫不及待地在一开始就把东西准备好。
映射到代码上就是我先创建好一个对象,但是可能没有被使用,一等到有用户要用,立马给用户,这中间没有多余的动作;
#include<bits/stdc++.h>
#include<mutex>
using namespace std;
namespace hunger_instance {//饿汉模式class Instance{public:static Instance* GetInstance(){return &_ins;}void f(){cout << "获取到了一个单例对象..." << endl;}private:Instance(const Instance&) = delete;Instance() = default;private:static Instance _ins;};Instance Instance::_ins;
}
代码中可以很好的体现出饿汉性质,_ins先初始化好了,用户可以直接通过域名调用GetInstance()获得单例对象地址;
懒汉模式
懒汉核心特点是在需要使用单例对象时才进行创建,即延迟加载。不会像饿汉方式一样,先把对象创建好,用的时候直接拿,懒汉不会先创建好对象,而是需要时才创建;
namespace lazy_instance
{std::mutex mtx;//饿汉模式class Instance{public:static Instance* GetInstance(){if (_ins == nullptr){{std::lock_guard<std::mutex>lock(mtx); if (_ins == nullptr){_ins = new Instance();}}}return _ins; }void f(){cout << "获取到了一个单例对象..." << endl;}private:Instance(const Instance&) = delete;Instance() = default;private:static Instance* _ins;};Instance* Instance::_ins = nullptr;
}
由于不是在类外先创建好的,所以我们不能使用普通对象,以为普通对象类外一初始化就是实例化了;
所以懒汉模式的对象是指针;类外初始化为空指针;
与饿汉模式另一点不同的是GetInstance方法,这里因为会存在线程安全所以需要用到互斥锁,以及双层循环保证只new一个对象;
如何理解懒汉模式的双层判断解决线程安全?
这里我以3个线程为例,分别为1、2、3号线程,同时要获取单例对象;
假设是1号线程先拿到了锁,还没有new呢,对象这个时候还是nullptr,但是这个时候2号线程也通过了第一层判断进来了,阻塞在了锁处,因为拿不到锁;
然后1号线程创建完对象,释放锁给2号线程,2号线程进来后,需要看一看对象是不是已经创建好了,2号对象发现对象指针不为空,说明已经创建好了,所以什么也不用干释放锁;也可以拿到对象指针;
3号线程这时候来了,在第一层判断处,他就发现指针不为空,那我直接return _ins就好了;
总结:双层判断是必要的,第一个判断很简单,就是避免进入该方法的线程避免在指针不为空的情况下还new;
第二层循环配合锁是对象还没创建完时,避免进入第一层循环内部的多个线程多次new对象;
相关文章:
设计模式-单例设计模式
目录 什么是单例设计模式? 为什么要使用单例模式? 资源方面 数据一致方面 系统性能方面 代码维护方面 如何设计单例类? 在说模式之前,我们需要先知道怎么设计才可以让一个类只能有一个实例化对象呢? 饿汉模式…...
Nextjs15 实战 - React Notes CURD 实现
本专栏内容均可在Github:notes_04 找到 完整项目使用技术栈: Nextjs15 MySQL Redis Auth Prisma i18n strapi Docker vercel 一、本节目标 本篇我们来实现右侧笔记CURD部分。 一、效果 当点击 New 按钮的时候进入编辑界面: 当点击…...
【KWDB 创作者计划】架构设计与AIoT场景实践
产品定位与核心价值主张 架构设计与技术实现 分布式架构设计 多模存储引擎实现 云边端协同机制 核心技术创新解析 就地计算技术 自适应时序引擎 混合事务处理 性能优化技术体系 高效存储机制 查询加速策略 资源管理与隔离 行业解决方案与典型应用 工业物联网平台…...
DeepSeek底层揭秘——《推理时Scaling方法》技术对比浅析
4月初,DeepSeek 提交到 arXiv 上的最新论文正在 AI 社区逐渐升温。 笔者尝试对比了“关于推理时Scaling”与现有技术,粗浅分析如下: 与LoRA的对比 区别: 应用场景:LoRA是一种参数高效微调方法,主要用于在…...
Spring MVC与Spring Boot文件上传配置差异对比及文件上传关键类详细说明与对比
一、Spring MVC与Spring Boot文件上传配置差异对比 1. 配置方式差异 框架配置方式依赖管理自动配置Spring MVC需手动配置MultipartResolver(如StandardServletMultipartResolver)需自行引入commons-fileupload等依赖无,默认不启用文件上传支…...
Linux网络配置与测试
目录 一.与网络配置相关的命令 1.1ifconfig命令 1.1.1作用 1.1.2网络接口的信息 接口信息的组成 1.1.3显示所有网卡包括没有启动的网卡 1.1.4查看指定网络接口 1.1.5开启或关闭网卡 1.1.6设置临时虚拟网卡 1.1.7网络通讯情况 编辑 1.1.8临时修改网卡属性 1.2hos…...
游戏赛季和数据处理
问题 游戏从无赛季到赛季机制会涉及哪些问题: 如何改动,增加赛季机制,涉及要修改的代码量最少如何改动,账号、角色部分数据继承问题,涉及要修改的代码量最少账号下角色的永久服共享或是永久服独立,需要做…...
京东店铺托管7*16小时全时护航
内容概要 京东店铺托管服务的*716小时全时护航模式,相当于给商家配了个全年无休的"运营管家"。专业团队每天从早7点到晚11点实时盯着运营数据和商品排名,连半夜流量波动都能通过智能系统秒级预警。这种全天候服务可不是单纯拼人力——系统自动…...
HTTP的Keep-Alive是什么?TCP 的 Keepalive 和 HTTP 的 Keep-Alive 是一个东西吗?
HTTP的Keep-Alive: HTTP Keep-Alive 是一种机制,允许客户端和服务器在单个 TCP 连接 上发送多个 HTTP 请求 和 响应,而不是每次请求和响应后都关闭连接。它的主要目的是提高性能,减少连接的开销,优化通信效率。 工作…...
使用scoop一键下载jdk和实现版本切换
安装 在 PowerShell 中输入下面内容,保证允许本地脚本的执行: set-executionpolicy remotesigned -scope currentuser然后执行下面的命令安装 Scoop: iwr -useb get.scoop.sh | iex国内用户可以使用镜像源安装:powershell iwr -us…...
PPIO × UI-TARS:用自然语言操控电脑,AI Agent 的极致体验
Manus的爆火预示着AI 正在从单纯的文本生成和图像识别迈向更复杂的交互场景。字节跳动近期推出的开源项目 UI-TARS Desktop 为我们展示了一种全新的可能性:能够通过自然语言理解和处理来控制计算机界面。这款工具代表了人工智能与人机交互领域的重大突破,…...
PG:incorrect prev-link
目录 WAL日志中"incorrect prev-link"错误解决方案错误原因分析解决步骤典型修复案例 WAL日志中"incorrect prev-link"错误解决方案 错误原因分析 WAL日志的prev-link字段用于确保日志记录的连续性。当出现incorrect prev-link 2/754ECB0 at 2/8000028错…...
SQL Server 数据库邮件配置失败:SMTP 连接与权限问题
问题现象: 配置数据库邮件时,发送测试邮件失败,提示 “邮件无法发送到 SMTP 服务器,操作超时”(错误 14661)或 “服务器拒绝发件人地址”(错误 15009)。 快速诊断 检查数据库邮件配置…...
深入浅出动态规划:从基础到蓝桥杯实战(Java版)
引言:为什么你需要掌握动态规划? 动态规划(DP)是算法竞赛和面试中的常客,不仅能大幅提升解题效率(时间复杂度通常为O(n)或O(n))[4],更是解决复杂优化问题的利器。统计显示ÿ…...
获取cookie的chrome插件:Get cookies.txt LOCALLY
接上一篇,在下载视频的时候需要网站的cookie,下面介绍一款可以获取网站cookie的chrome插件 https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc?utm_sourceitem-share-cb 备注需要科学上网 【使用方…...
opencv无法设置禁用RGB转换问题
树莓派连接摄像头,摄像头输出格式为YUYV(YUV422)。 通过执行 v4l2-ctl --list-formats --device/dev/video0 可以看的具体的摄像头的数据格式。 使用opencv获取视频流,通过cap.set(cv2.CAP_PROP_CONVERT_RGB, 0)设置禁用自动转换RGB格式,但是打印输出…...
Ansible:roles角色
文章目录 Roles角色Ansible Roles目录编排Roles各目录作用创建 roleplaybook调用角色调用角色方法1:调用角色方法2:调用角色方法3: roles 中 tags 使用实战案例 Roles角色 角色是ansible自1.2版本引入的新特性,用于层次性、结构化…...
SAP系统采购信息记录失效
问题:采购信息记录失效 现象:最初主数据导入完成之后,单元测试的时采购信息记录是有效的,中间经过配置的变化,集成测试初期发现采购信息记录全部失效。 原因: 单元测试时发现采购订单里面的条件类型…...
JavaWeb 课堂笔记 —— 04 Ajax
本系列为笔者学习JavaWeb的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员JavaWeb开发教程,实现javaweb企业开发全流程(涵盖SpringMyBatisSpringMVCSpringBoot等)》,章节分布参考视频教程,为同样学习…...
Pandas 库
Pandas 是一个开源的数据分析和数据处理库,它是基于 Python 编程语言的。 Pandas 提供了易于使用的数据结构和数据分析工具,特别适用于处理结构化数据,如表格型数据 Pandas 是数据科学和分析领域中常用的工具之一,它使得用户能够…...
4.8学习总结
完成摆动序列的算法题(比较难,想不出方法) 学习了HashMap,TreeMap 的源码(看完一遍对其理解没有太清楚,还需再多刷几遍理解源码及其底层逻辑的概念) 学习了可变参数和Collections工具类...
C语言之九九乘法表
一、代码展示 二、运行结果 三、代码分析 首先->是外层循环是小于等于9的 然后->是内层循环是小于等于外层循环的 最后->就是\n让九九乘法表的格式更加美观(当然 电脑不同 有可能%2d 也有可能%3d) 四、与以下素数题目逻辑相似 五、运行结果...
【Linux操作系统】:信号
Linux操作系统下的信号 一、引言 首先我们可以简单理解一下信号的概念,信号,顾名思义,就是我们操作系统发送给进程的消息。举个简单的例子,我们在写C/C程序的时候,当执行a / 0类似的操作的时候,程序直接就挂…...
skynet.call使用详解
目录 skynet.call 详细解析1. 函数签名与参数2. 内部实现机制3. 会话ID与协程调度4. 超时与错误处理5. 返回值处理6. 协议类型的影响7. skynet.call vs skynet.send8. 示例代码分析9. 最佳实践10. 总结 skynet.call 详细解析 1. 函数签名与参数 函数签名: skynet…...
uniapp 打包 H5 向 打包的APP 使用 @dcloudio/uni-webview-js 传值
1.安装 dcloudio/uni-webview-js npm install dcloudio/uni-webview-js -save 这个模块的 uni. 会与H5的uniapp的 uni. 冲突,所以需要改下名称,一共需要改3处 2.引入并使用 import uniWeb from dcloudio/uni-webview-js;uniWeb.postMessage({data: {action: message,content…...
c语言 文件操作
c语言 文件操作 one 打开/usr/dev.txt文件,在第1行 覆盖写入 "MAC1q23456789" #include <fcntl.h> #include <unistd.h> #include <string.h> int main() { const char *line_1 "MAC1q23456789\n"; // 要写入的内容…...
企业电子招投标采购系统——功能模块功能描述+数字化采购管理 采购招投标
功能描述 1、门户管理:所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含:招标公告、非招标公告、系统通知、政策法规。 2、立项管理:企业用户可对需要采购的项目进行立项申请,并提交审批,查看…...
Python 序列构成的数组(序列的增量赋值)
序列的增量赋值 增量赋值运算符 和 * 的表现取决于它们的第一个操作对象。简单起 见,我们把讨论集中在增量加法()上,但是这些概念对 * 和其他 增量运算符来说都是一样的。 背后的特殊方法是 iadd (用于“就地加法”&…...
力扣hot100【链表】
160.相交链表 题目 我的思路:两个链表一长一短,先把长的提前遍历使两个链表的长度相等,然后同时遍历,如果遍历的节点相等时说明相交,否则不相交。 /*** Definition for singly-linked list.* struct ListNode {* …...
PyTorch 生态迎来新成员:SGLang 高效推理引擎解析
SGLang 现已正式融入 PyTorch 生态系统!此次集成确保了 SGLang 符合 PyTorch 的技术标准与最佳实践,为开发者提供了一个可靠且社区支持的框架,助力大规模语言模型(LLM)实现高效且灵活的推理。 如需深入了解 PyTorch…...
C++ Primer Plus 编程练习题 第六章 分支语句和逻辑运算符
1.大小写转换 使用cctype库里的函数进行大小写转换,但要注意使用toupper或tolower时要进行强制类型转换,否则会输出ASCII值 #include <iostream> #include<cctype> using namespace std;int main() {cout << "请输入字符串(大…...
一文详解OpenGL环境搭建:Windows使用CLion配置OpenGL开发环境
在计算机图形学的广阔领域中,OpenGL作为行业标准的图形库,为开发者提供了强大的工具集来创建从简单的2D图形到复杂的3D世界。然而,对于初学者和经验丰富的开发者而言,选择一个合适的开发环境是迈向成功的第一步。尤其是在Windows平台上,配置一个既支持现代C++编程实践又能…...
一次奇怪的enq: TX - row lock contention锁问题处理
某天上午客户告知数据库库有锁导致数据库卡死,需排查出问题的原因,从根本上解决问题。 按正常步骤,查询V$SESSION中BLOCKING_SESSION列不为空的,发现没有进程互相阻塞的情况;而查询ACTIVE会话,则有大量进程…...
STL常用容器整理
STL常用容器操作整理 STL常用容器操作整理(string/vector/set/map)一、string(字符串)构造函数元素访问修改操作容量操作子串与查找 二、vector(动态数组)构造函数元素访问修改操作容量操作 三、set&#x…...
深入 PostgreSQL 内部:5 个关键阶段拆解查询处理全流程
引言 当您向 PostgreSQL 发送查询时,后端会经历多个处理阶段。每个阶段承担着不同的职责,以确保您能在最短时间内获得准确响应。虽然这些阶段可能庞大而复杂,但理解它们在查询处理中的角色对 PostgreSQL 开发者至关重要。本文将概述每个查询…...
解析 LILIkoi 光纤力传感器:FBG 原理铸就耐高温抗干扰优势
LILIkoi光纤力传感器通过光纤光栅(FBG)技术实现高精度力测量。其核心原理基于光纤内光栅栅距的微小变化,用以感知外界施加的力。该传感器在高温、强辐射等恶劣环境中表现出色,能够有效抵抗电磁干扰和温度漂移。凭借卓越的性能&…...
SU-YOLO:基于脉冲神经网络的高效水下目标检测模型解析
论文地址:https://arxiv.org/pdf/2503.24389 目录 一、论文概述 二、创新点解析 1. 基于脉冲的水下图像去噪(SpikeDenoiser) 原理与结构 2. 分离批归一化(SeBN) 原理与结构 3. 优化的残差块(SU-Block) 原理与结构 三、代码复现指南 环境配置 模型训练 四、…...
有关eeprom以及pwm
a0 a1就是对应的 芯片的 写和读 0写 1读 使用操作 主函数读一次 然后信息里一直写入。 用level设置挡位 如 10个格子 设置2 3 这样占空比就有了...
JMeter教程|0到1学会接口性能压测第14课-JMeter接口性能测试全流程讲解
Apache JMeter是一款纯java编写负载功能测试和性能测试开源工具软件。相比Loadrunner而言,JMeter小巧轻便且免费,逐渐成为了主流的性能测试工具,是每个测试人员都必须要掌握的工具之一。 本文以百度搜索接口为例,全流程讲解JMeter接口性能测试。从JMeter下载安装到编写一个…...
系统思考:问题诊断
“做事不怕困难,怕的是不明白困难出在哪里。” —— 亨利福特 最近发现,有些领导者或者团队,常常急于给出解决方案,却忽视了最关键的一步——诊断问题的根源。团队甚至在集体心智模式的影响下,连问题本身都搞错了方向…...
有效压缩 Hyper-v linux Centos 的虚拟磁盘 VHDX
参考: http://www.360doc.com/content/22/0505/16/67252277_1029878535.shtml VHDX 有个不好的问题就是,如果在里面存放过文件再删除,那么已经使用过的空间不会压缩,导致空间一直被占用。那么就需要想办法压缩空间。 还有一点&a…...
使用 redis 实现消息队列
方案1: 使用list做消息队列问题1: 如何保证消息不丢失问题 2: 重复消费/幂等 方案 2: zset实现消息队列方案 3: 发布/订阅(pub/sub)问题1: 如何保证消息不丢失问题 2: 重复消费/幂等 方案 4: Stream 实现消息队列问题1: 如何保证消息不丢失问题 2: 重复消费/幂等 方案1: 使用li…...
2025 XYCTF Pwn-wp(含附件)
前言 总体来说Pwn方向题目难度属于中等,属于那种一眼看不出要咋做,但多试试又能做出来的那种,比赛的时候甚至有几只队伍AK了Pwn方向。感觉题目还是很不错的尽管比赛中有一些小意外像是有些题目附件给错了,但是XYCTF的师傅们都是无偿出题纯热爱向大伙分享自己的题目…...
verilog有符号数的乘法
1、单周期乘法器 对于低速要求的乘法器,可以简单的使用 * 实现。 module Mult(input wire [7:0] multiplicand ,input wire [7:0] multipliter ,output wire [7:0] product);assign product multiplicand * multipliter …...
【python3】关于等额本金和等额本息计算
【python3】关于等额本金和等额本息计算 1.背景2.计算3.总结4.推导 1.背景 在贷款买房的宝子们一定有了解等额本金和等额本息,年轻的时候只听销售在那里计算, 您可能听得云里雾里。 等额本金:每个月还的本金固定,利息逐渐减少。…...
git怎么删除远程分支
删除远程分支 引言删除远程分支查看远程分支查看远程分支详情删除远程分支 引言 本文旨在记录一下,git如何通过命令行删除远程分支。 删除远程分支 查看远程分支 使用指令: git branch -r查看远程分支详情 使用指令: git remote show …...
【C++】函数直接返回bool值和返回bool变量差异
函数直接返回bool值和返回bool变量差异 背景 在工作中遇到一个比较诡异的问题,场景是给业务方提供的SDK有一个获取状态的函数GetStatus,函数的返回值类型是bool,在测试过程中发现,SDK返回的是false,但是业务方拿到的…...
蓝桥杯-蓝桥幼儿园(并查集)
并查集的核心思想 并查集主要由两个操作构成: Find:查找某个元素所在集合的根节点。并查集的特点是,每个元素都指向它自己的父节点,根节点的父节点指向它自己。查找过程中可以通过路径压缩来加速后续的查找操作,即将路…...
Ensemble of differential evolution variants(EDEV)
差分进化变体的集成1 在这项研究中,一个基于多种群的框架(MPF)被提议用于多个差分进化变体的集合。与PAP2不同,PAP通过时间预算分配策略和个体移民算子实现算法组合,MPF将整个种群划分为子种群,包括几个指…...
《AI开发工具和技能实战》第1集 Windows CMD 命令行操作指南:从基础到进阶
第1集 Windows CMD 命令行操作指南:从基础到进阶 在日常使用 Windows 系统时,命令提示符(Command Prompt,简称 CMD)是一个强大且灵活的工具。无论是文件管理、系统配置,还是网络诊断,CMD 都能提…...