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

设计模式:单例模式

复习一下:

单例模式(Singleton Pattern)

原理:

单例模式确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。它通过将类的构造函数设为私有,防止外部代码直接实例化该类。同时,提供一个静态方法来获取唯一的实例。在首次调用获取实例的方法时,会创建这个实例,之后的调用都返回这个已创建的实例。

示例代码:
class Singleton {
private:
    static Singleton* instance;
    Singleton() {}
public:
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton;
        }
        return instance;
    }
};
Singleton* Singleton::instance = nullptr;
使用场景:

适用于资源共享的情况,如数据库连接池。因为只需要一个数据库连接池实例来管理连接,避免多次创建和销毁连接池带来的开销。还用于日志系统,全局只有一个日志对象记录各种日志信息,方便统一管理和配置。

优化

上面的代码虽然实现了单例模式,但存在线程安全问题。在多线程环境下,多个线程可能同时检查到 instance 为 nullptr,从而创建多个实例。可以使用双重检查锁定(Double-Checked Locking)或者静态局部变量的方式来优化。

  • 双重检查锁定

    双重检查锁定会在第一次检查 instance 是否为 nullptr 之后加锁,再次检查 instance 是否为 nullptr,以确保只有一个线程能创建实例。

    #include <mutex>
    
    class Singleton {
    private:
        static Singleton* instance;
        static std::mutex mutex_;
        Singleton() {}
    public:
        static Singleton* getInstance() {
            if (instance == nullptr) {
                std::lock_guard<std::mutex> lock(mutex_);
                if (instance == nullptr) {
                    instance = new Singleton;
                }
            }
            return instance;
        }
    };
    Singleton* Singleton::instance = nullptr;
    std::mutex Singleton::mutex_;
    
  • 静态局部变量

    C++11 之后,静态局部变量的初始化是线程安全的,因此可以使用静态局部变量来实现单例模式。

    class Singleton {
    private:
        Singleton() {}
    public:
        static Singleton& getInstance() {
            static Singleton instance;
            return instance;
        }
    };
    

    这种方式更为简洁,并且自动处理了线程安全问题,也避免了手动管理内存。

    使用静态局部变量的方式来实现单例模式,其原理主要基于静态局部变量的两个关键特性:延迟初始化和线程安全初始化。

    延迟初始化

    静态局部变量是在程序第一次执行到其定义处时才进行初始化的。也就是说,只有当首次调用包含该静态局部变量的函数时,这个静态局部变量才会被创建并初始化。

    在单例模式的实现中,静态局部变量的这种特性能够确保单例实例是在真正需要使用它的时候才被创建,而非在程序启动阶段就创建,这样可以避免不必要的资源浪费。

    线程安全初始化

    C++11 标准规定,静态局部变量的初始化是线程安全的。这意味着在多线程环境下,即使多个线程同时调用包含静态局部变量的函数,也能保证该静态局部变量只会被初始化一次。

    当多个线程同时尝试访问并初始化这个静态局部变量时,标准要求编译器必须保证只有一个线程能够执行初始化操作,其他线程需要等待初始化完成后才能继续执行。这样一来,就确保了单例模式中实例的唯一性。

相关文章:

  • AI大模型与知识生态:重构认知的新时代引擎
  • 将mongdb中文档转储到mysql设计思路
  • 众趣科技丨沉浸式 VR 体验,助力酒店民宿数字化营销宣传
  • Maya云渲染工作流,提升渲染速度
  • C++蓝桥杯填空题(攻克版)
  • NLP高频面试题(三十八)——什么是LLM的灾难性遗忘?如何避免灾难性遗忘?
  • C++手写std::function
  • Three.js关键帧动画不连续正放、倒放出现的部分问题
  • 【PVR Review】《A Review of Palmar Vein Recognition》
  • atypica.AI:用「语言模型」为「主观世界」建模
  • Redis的哨兵
  • 深度学习基础--CNN经典网络之分组卷积与ResNext网络实验探究(pytorch复现)
  • EasyX 图形库学习笔记
  • c#程序结构
  • 单北斗终端:铸就国产科技脊梁
  • 告别 ifconfig:为什么现代 Linux 系统推荐使用 ip 命令
  • 【蓝桥杯Web】2022年十三届省赛大学组真题 冬奥大抽奖 介绍 蓝桥云课庆冬奥需要举行一次抽奖活动,我们一起做一个页面提供给云课冬奥抽奖活动使用。
  • 【算法】【蓝桥23国A软件C】四版代码思路分析与逐步优化
  • influxdb数据导出笔记
  • 【结肠息肉AI论文集】Shallow Attention Network for Polyp Segmentation
  • wordpress如何弄添加框/网站百度关键词优化
  • wordpress建多语言分站/seo整站优化哪家好
  • 网站设置的参数/北京网站seo优化推广
  • 利于seo的网站设计/新手做销售怎么开发客户
  • 长沙制作网站的公司/域名注册信息查询
  • 获取网站访客qq代码/腾讯朋友圈广告怎么投放