单例模式再简单不过了!

单例模式

  • 1. 概述
  • 2. 应用场景
  • 3. 实现细节
  • 4. 实现
    • 4.1 饿汉式(Eager Initialization)
    • 4.2 懒汉式(Lazy Initialization)
    • 4.3 线程安全懒汉式(Thread-safe Lazy Initialization)
      • 1. 使用互斥量加锁
      • 2. 双重判断
      • 3. 使用 std::call_once
    • 4.4 静态局部变量实现单例模式(C++11开始)

1. 概述

确保类在程序中只有一个实例,并提供一个全局访问点。

2. 应用场景

单例模式的使用场景非常广泛,主要集中在需要确保类在程序中只有一个实例,并且提供一个全局访问点的场景。以下是一些具体的使用场景:

  • 资源共享
    数据库连接池:在程序中,数据库连接是非常宝贵的资源,使用单例模式可以确保整个程序只使用一个数据库连接池实例,从而有效管理数据库连接,避免连接泄露和频繁开启/关闭连接的开销。
    线程池:类似于数据库连接池,线程池也是程序中重要的资源。使用单例模式可以确保整个程序只使用一个线程池实例,以便统一管理和调度线程,提高程序的性能和响应速度。

  • 配置管理
    配置文件读取:在程序启动时或运行过程中,可能需要读取配置文件来获取一些必要的配置信息(如数据库连接信息、日志级别等)。使用单例模式可以确保整个程序只使用一个配置类实例来读取和存储这些配置信息,方便程序其他部分随时获取。

  • 日志记录
    在编写日志系统时,使用单例模式可以确保整个程序只使用一个日志类实例来记录日志信息。这样可以保证日志信息的统一性和一致性,便于后续的日志分析和问题追踪。

  • 对象缓存
    对于一些创建成本较高或需要频繁访问的对象,可以使用单例模式进行缓存。通过缓存这些对象,可以提高程序的性能,减少不必要的创建和销毁开销。

  • GUI应用程序
    在GUI应用程序中,可能需要创建全局唯一的窗口、对话框等界面元素。使用单例模式可以确保这些界面元素在整个程序中只有一个实例,避免重复创建和显示相同的界面元素。

  • 状态管理
    在管理程序的状态(如用户登录状态、程序运行状态等)时,可以使用单例模式来确保状态的一致性和准确性。通过单例模式,可以确保整个程序在访问这些状态时,都是通过一个统一的入口来进行的。

  • 资源管理
    在管理系统资源(如内存、文件等)时,单例模式也可以发挥重要作用。通过单例模式,可以确保资源的分配和释放都是由一个统一的实例来管理的,从而避免资源泄漏或重复释放资源的问题。

3. 实现细节

  • 如何确保只有一个实例
    默认构造函数私有化,赋值运算符重,防止外部能够创建该类以及其它类继承该类。
    确保线程安全,防止多个线程同时创建该类对象。
  • 提供全局访问点

4. 实现

总共有四种实现方式:饿汉式、懒汉式、线程安全懒汉式、局部静态变量式

4.1 饿汉式(Eager Initialization)

在程序开始时就创建了唯一的实例,缺点是,如果该单例无需使用,依然会消耗资源。优点是线程安全的。

class Singleton {
private:// 私有构造函数,防止外部创建实例Singleton() {}// 静态实例,立即初始化static Singleton instance;public:// 删除拷贝构造和赋值运算符,防止拷贝对象Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 静态方法获取单例实例static Singleton& getInstance() {return instance;}
};// 在类外初始化静态成员
Singleton Singleton::instance;int main() {Singleton& s1 = Singleton::getInstance();Singleton& s2 = Singleton::getInstance();// s1 和 s2 是同一个实例
}

4.2 懒汉式(Lazy Initialization)

在第一次获取实例时才实例化,所以当无需使用该类情况下可节省内存,但是在多线程中可能会出现同时进行实例化的情况,是非线程安全

class Singleton {
private:// 私有构造函数,防止外部创建实例或继承该类Singleton() {}// 静态实例,立即初始化static Singleton instance;public:// 删除拷贝构造和赋值运算符,防止拷贝对象Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 静态方法获取单例实例static Singleton& getInstance() {return instance;}
};// 在类外初始化静态成员
Singleton Singleton::instance;int main() {Singleton& s1 = Singleton::getInstance();Singleton& s2 = Singleton::getInstance();// s1 和 s2 是同一个实例
}

4.3 线程安全懒汉式(Thread-safe Lazy Initialization)

1. 使用互斥量加锁

就是在懒汉式的基础上加锁,使用互斥量确保同一时刻仅有一个线程实例化该对象,但在每次获取实例时都会加锁,影响性能

#include <mutex>class Singleton {
private:// 私有构造函数Singleton() {}// 静态指针,初始化为 nullptrstatic Singleton* instance;// 互斥量static std::mutex mtx;public:// 删除拷贝构造和赋值运算符,防止拷贝对象Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton* getInstance() {// 加锁std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr) {instance = new Singleton();}return instance;}
};// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;int main() {Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();// s1 和 s2 是同一个实例
}

2. 双重判断

在加锁前再进行一次判断,双重判断,避免每次都要加锁,提高性能。

#include <mutex>class Singleton {
private:// 私有构造函数Singleton() {}// 静态指针,初始化为 nullptrstatic Singleton* instance;// 互斥量static std::mutex mtx;public:// 删除拷贝构造和赋值运算符,防止拷贝对象Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton* getInstance() {if (instance == nullptr) {// 加锁std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr) {instance = new Singleton();}}return instance;}
};// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;int main() {Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();// s1 和 s2 是同一个实例
}

3. 使用 std::call_once

#include <mutex>class Singleton {
private:Singleton() {}static Singleton* instance;static std::once_flag initFlag;public:Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton* getInstance() {std::call_once(initFlag, []() { instance = new Singleton(); });return instance;}
};// 初始化静态成员
Singleton* Singleton::instance = nullptr;
std::once_flag Singleton::initFlag;int main() {Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();// s1 和 s2 是同一个实例
}

4.4 静态局部变量实现单例模式(C++11开始)

懒加载instance 只在第一次调用 getInstance() 时创建,后续直接返回同一个对象。
线程安全C++11 保证了静态局部变量的初始化是线程安全的,因此无需显式的锁机制。
简洁性:相比使用锁或 std::call_once,这种方式的代码更加简洁。

class Singleton {
private:// 私有构造函数,防止外部创建实例Singleton() {}public:// 删除拷贝构造和赋值运算符,防止拷贝对象Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;// 静态方法获取单例实例static Singleton& getInstance() {static Singleton instance;  // 静态局部变量,只有第一次调用时初始化,且线程安全return instance;}
};int main() {Singleton& s1 = Singleton::getInstance();Singleton& s2 = Singleton::getInstance();// s1 和 s2 是同一个实例
}

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

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

相关文章

GraphPad Prism 10 for Mac/Win:高效统计分析与精美绘图的科学利器

GraphPad Prism 10 是一款专为科研工作者设计的强大统计分析与绘图软件&#xff0c;无论是Mac还是Windows用户&#xff0c;都能享受到其带来的便捷与高效。该软件广泛应用于生物医学研究、实验设计和数据分析领域&#xff0c;以其直观的操作界面、丰富的统计方法和多样化的图表…

【HuggingFace Transformers】OpenAIGPTModel源码解析

OpenAIGPTModel源码解析 1. GPT 介绍2. OpenAIGPTModel类 源码解析 说到ChatGPT&#xff0c;大家可能都使用过吧。2022年&#xff0c;ChatGPT的推出引发了广泛的关注和讨论。这款对话生成模型不仅具备了强大的语言理解和生成能力&#xff0c;还能进行非常自然的对话&#xff0c…

MapSet之二叉搜索树

系列文章&#xff1a; 1. 先导片--Map&Set之二叉搜索树 2. Map&Set之相关概念 目录 前言 1.二叉搜索树 1.1 定义 1.2 操作-查找 1.3 操作-新增 1.4 操作-删除(难点) 1.5 总体实现代码 1.6 性能分析 前言 TreeMap 和 TreeSet 是 Java 中基于搜索树实现的 M…

图形语言传输格式glTF和三维瓦片数据3Dtiles(b3dm、pnts)学习

文章目录 一、3DTiles二、b3dm三、glTF1.glTF 3D模型格式有两种2.glTF 场景描述结构和坐标系3.glTF的索引访问与ID4.glTF asset5.glTF的JSON结构scenesscene.nodes nodesnodes.children transformations对外部数据的引用buffers 原始二进制数据块&#xff0c;没有固有的结构或含…

表单项标签简单学习

目录 1. 单选框 radio​编辑​编辑​编辑​编辑 2. 复选框 checkbox ​编辑​编辑​编辑 3. 隐藏域 hidden 4. 多行文本框 textarea​编辑​编辑 5. 下拉框 select​编辑​编辑 6. 选择头像​编辑​编辑 <!DOCTYPE html> <html lang"en"> <head&…

自用NAS系列1-设备

拾光坞 拾光坞多账号绑定青龙面板SMBWebdav小雅alist下载到NASDocker安装迅雷功能利用qBittorrentEEJackett打造一站式下载工具安装jackett插件 外网访问内网拾光客户端拾光穿透公网ipv6路由器配置ipv6拾光坞公网验证拾光坞域名验证 拾光坞 多账号绑定 手机注册拾光坞账号&am…

GEE数据集:加拿大卫星森林资源调查 (SBFI)-2020 年加拿大森林覆盖、干扰恢复、结构、物种、林分年龄以及 1985-2020 年林分替代干扰的信息

目录 简介 数据集后处理 数据下载链接 矢量属性 代码 代码链接 引用 许可 网址推荐 0代码在线构建地图应用 机器学习 加拿大卫星森林资源调查 (SBFI) 简介 卫星森林资源清查&#xff08;SBFI&#xff09;提供了 2020 年加拿大森林覆盖、干扰恢复、结构、物种、林分…

海外云手机是否适合运营TikTok?

随着科技的迅猛发展&#xff0c;海外云手机逐渐成为改变工作模式的重要工具。这种基于云端技术的虚拟手机&#xff0c;不仅提供了更加便捷、安全的使用体验&#xff0c;还在电商引流和海外社媒管理等领域展示了其巨大潜力。那么&#xff0c;海外云手机究竟能否有效用于运营TikT…

828华为云征文 | Flexus X 实例服务器网络性能深度评测

引言 随着互联网应用的快速发展&#xff0c;网络带宽和性能对云服务器的表现至关重要。在不同的云服务平台上&#xff0c;即便配置相同的带宽&#xff0c;实际的网络表现也可能有所差异。因此&#xff0c;了解并测试服务器的网络性能变得尤为重要。本文将以华为云X实例服务器为…

Open-Sora代码详细解读(1):解读DiT结构

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;目前开源的DiT视频生成模型不是很多&#xff0c;Open-Sora是开发者生态最好的一个&#xff0c;涵盖了DiT、时空DiT、3D VAE、Rectified Flow、因果卷积等Diffusion视频生成的经典知识点。本篇博客从Open-S…

【MySQL】MySQL基础

目录 什么是数据库主流数据库基本使用MySQL的安装连接服务器服务器、数据库、表关系使用案例数据逻辑存储 MySQL的架构SQL分类什么是存储引擎 什么是数据库 mysql它是数据库服务的客户端mysqld它是数据库服务的服务器端mysql本质&#xff1a;基于C&#xff08;mysql&#xff09…

linux系统中,计算两个文件的相对路径

realpath --relative-to/home/itheima/smartnic/smartinc/blocks/ruby/seanet_diamond/tb/parser/test_parser_top /home/itheima/smartnic/smartinc/corundum/fpga/lib/eth/lib/axis/rtl/axis_fifo.v 检验方式就是直接在当前路径下&#xff0c;把输出的路径复制一份&#xff0…

Nginx跨域运行案例:云台控制http请求,通过 http server 代理转发功能,实现跨域运行。(基于大华摄像头WEB无插件开发包)

文章目录 引言I 跨域运行案例开发资源测试/生产环境,Nginx代理转发,实现跨域运行本机开发运行II nginx的location指令Nginx配置中, 获取自定义请求header头Nginx 配置中,获取URL参数引言 背景:全景监控 需求:感知站点由于云台相关操作为 http 请求,http 请求受浏览器…

Redis-主从集群

主从架构 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离。 主从数据同步原理 全量同步 主从第一次建立连接时&#xff0c;会执行全量同步&#xff0c;将master节点的所有数据都拷贝给sla…

34465A-61/2 数字万用表(六位半)

34465A-61/2 数字万用表(六位半) 文章目录 34465A-61/2 数字万用表(六位半)前言一、测DC/AC电压二、测DC/AC电流四、测电阻五、测电容六、测二极管七、保存截图流程前言 1、6位半数字万用表通常具有200,000个计数器,可以显示最大为199999的数值。相比普通数字万用表,6位半…

注册安全分析报告:熊猫频道

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【笔记】Java | 三目运算符和Math函数的比较

实际效果 比较两数并赋值&#xff0c;如下两种方法的耗时不会有差异。 result Math.min(result, subLen);result result < subLen ? result : subLen; 源码解析 因为源码Math.min的源码本质就算三目运算符的比较&#xff0c;所以执行结果是一样的。 三目运算符简介 概…

怎么强制撤销excel工作表保护?

经常不是用的Excel文件设置了工作表保护&#xff0c;偶尔打开文件的时候想要编辑文件&#xff0c;但是发现忘记了密码&#xff0c;那么这种情况&#xff0c;我们怎么强制撤销excel工作表保护&#xff1f;今天分享两种解决方法。 方法一、 将excel文件转换为其他文件格式&…

新品上市丨科学级新款制冷相机sM4040A/sM4040B

sM4040B科学级显微制冷相机 特性 sM4040B搭载了 GSENSE4040BSI 3.2 英寸图像传感器&#xff0c;针对传感器固有的热噪声&#xff0c;专门设计了高效制冷模块&#xff0c;使得相机传感器的工作温度比环境温度低达 35-40 度。针对制冷相机常见的低温结雾现象设计了防结雾机制&a…

二百五十九、Java——采集Kafka数据,解析成一条条数据,写入另一Kafka中(一般JSON)

一、目的 由于部分数据类型频率为1s&#xff0c;从而数据规模特别大&#xff0c;因此完整的JSON放在Hive中解析起来&#xff0c;尤其是在单机环境下&#xff0c;效率特别慢&#xff0c;无法满足业务需求。 而Flume的拦截器并不能很好的转换数据&#xff0c;因为只能采用Java方…