当前位置: 首页 > news >正文

设计模式十:单件模式 (Singleton Pattern)

单件模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。

单例模式有两种主要的初始化方式:饱汉模式(Lazy Initialization)和饿汉模式(Eager Initialization)。它们在实例创建的时机上有显著区别。

1. 饱汉模式 (Lazy Initialization)

饱汉模式也称为"懒加载"模式,只有在第一次请求实例时才创建单例对象。

特点:

  • 延迟初始化:实例在第一次调用getInstance()时才被创建

  • 节省资源:如果从未使用单例,则不会创建实例

  • 需要处理线程安全问题

基础实现(非线程安全):

class Singleton {
private:Singleton() {}static Singleton* instance;public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton();}return instance;}// 删除拷贝构造函数和赋值运算符Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};Singleton* Singleton::instance = nullptr;

 线程安全版本:

#include <mutex>class Singleton {
private:Singleton() {}static Singleton* instance;static std::mutex mtx;public:static Singleton* getInstance() {std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr){  instance = new Singleton();}return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

 此方法线程安全,但是锁的代价太高,每次访问都需要加锁,开销较大,需要优化 。

 双检查锁(但由于内存读写reorder不安全) :

#include <mutex>class Singleton {
private:Singleton() {}static Singleton* instance;static std::mutex mtx;public:static Singleton* getInstance() {if (instance == nullptr) {  // 第一次检查std::lock_guard<std::mutex> lock(mtx);if (instance == nullptr) {  // 第二次检查instance = new Singleton();}}return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mtx;

正常的逻辑是(1、先分配内存,2、最后再构造 ,3、把内存分配给instance ),但是由于内存读写reorder,可能会导致其他线程访问在第一次检查时读取了reorder(可能最开始的线程1、先分配内存,2、把内存分配给instance ,3、最后再构造)的非正确值(第2步的内存),出现错误。

C++11版本之后的跨平台实现(volatile) (线程安全)

std::atomic<Singleton*> Singleton::m_instance;
std::mutex Singleton::m_mutex;Singleton* Singleton::getInstance() {// 1. 首先以宽松内存序读取当前实例Singleton* tmp = m_instance.load(std::memory_order_relaxed);// 2. 获取内存栅栏,确保后续读取操作能看到之前的所有写入std::atomic_thread_fence(std::memory_order_acquire);if (tmp == nullptr) {std::lock_guard<std::mutex> lock(m_mutex);tmp = m_instance.load(std::memory_order_relaxed);if (tmp == nullptr) {tmp = new Singleton;// 3. 释放内存栅栏,确保新对象的构造对所有处理器可见std::atomic_thread_fence(std::memory_order_release);// 4. 以宽松内存序存储新实例m_instance.store(tmp, std::memory_order_relaxed);}}return tmp;
}

2. 饿汉模式 (Eager Initialization)

饿汉模式在程序启动时(静态初始化阶段)就创建单例实例。

特点:

  • 提前初始化:实例在程序启动时就被创建

  • 线程安全:因为实例在main()函数执行前就已创建

  • 可能浪费资源:即使从未使用单例,实例也会被创建

实现:

class Singleton {
private:Singleton() {}static Singleton* instance;public:static Singleton* getInstance() {return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};// 在程序启动时就初始化实例
Singleton* Singleton::instance = new Singleton();

使用静态变量的饿汉模式:

class Singleton {
private:Singleton() {}public:static Singleton& getInstance() {static Singleton instance;  // 静态变量在首次使用时初始化(C++11保证线程安全)return instance;}Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;
};

对比总结

特性饱汉模式饿汉模式
初始化时机第一次调用getInstance()时程序启动时
线程安全需要额外处理天生线程安全
资源占用按需分配,节省资源始终占用资源
实现复杂度较复杂(需处理线程安全)较简单
适用场景初始化耗时或资源占用大的对象初始化快且一定会使用的对象
http://www.lryc.cn/news/599744.html

相关文章:

  • 《设计模式之禅》笔记摘录 - 10.装饰模式
  • 一道检验编码能力的字符串的题目
  • C# WPF 实现读取文件夹中的PDF并显示其页数
  • 《Angular+Spring Boot:ERP前端采购销售库存协同架构解析》
  • Qt 数据库事务处理与数据安全
  • Orbbec开发---数据流与数据流操作
  • 输电线路观冰精灵在线监测装置:科技赋能电网安全的新利器
  • 智慧灯杆:不止于照明,塔能科技的城市感知网络野心
  • 微算法科技(NASDAQ:MLGO)采用分布式哈希表优化区块链索引结构,提高区块链检索效率
  • C 语言 | 结构体详解:自定义数据类型的艺术
  • 现代 C++ 开发工作流(VSCode / Cursor)
  • 多场景通用车辆计数算法助力暑期交通管理
  • 【质量管理】软件缺陷管理实施方案(专业版)
  • 华为网络整套架构常用配置
  • cacti漏洞CVE-2022-46169复现
  • ThreadLocal使用及其原理和注意点
  • 虚拟机docker elasticsearch启动失败
  • 07 51单片机之定时器
  • react+threejs实现自适应分屏查看/3D场景对比功能/双场景对比查看器
  • 二分查找----6.寻找两个正序数组的中位数
  • 基于深度学习的图像分类:使用Vision Transformer(ViT)实现高效分类
  • Lakehouse x AI ,打造智能 BI 新体验
  • 认识一下Qlib的158因子特征
  • Gitee Test:国产软件测试平台如何筑牢关键领域数字安全屏障
  • PI 思维升级 PI设计的典范转移:从阻抗思维到谐振控制
  • 主要分布在背侧海马体(dHPC)CA1区域(dCA1)的时空联合细胞对NLP中的深层语义分析的积极影响和启示
  • 杂谈:前端开发中的常见问题
  • 【机器学习之推荐算法】基于矩阵分解和损失函数梯度下降的协同过滤算法实现
  • 验证 GitHub Pages 的自定义域(Windows)
  • Power Compiler:漏电功耗、内部功耗、切换功耗及其计算方式(NLPM)