【多线程】线程安全的单例模式
创始人
2024-12-28 22:10:28
0

文章目录

  • 什么是单例模式
    • 饿汉实现方式
      • 饿汉实现模式的特点
    • 懒汉实现方式
    • 懒汉实现方式的特点

什么是单例模式

单例模式是一个设计模式,其目的是确保一个类只有一个实例,并提供一个全局的访问点来访问该实例。单例模式常用于需要控制资源数量的场景,比如数据库连接池、日志管理器等。下面介绍常见的单例模式的实现方式。

饿汉实现方式

观察下面代码:

class EagerSingleton { private:     // 私有构造函数,防止外部实例化     EagerSingleton() {}      // 禁用拷贝构造函数和赋值运算符     EagerSingleton(const EagerSingleton&) = delete;     EagerSingleton& operator=(const EagerSingleton&) = delete;      // 静态实例,类加载时初始化     static EagerSingleton instance;  public:     // 提供全局访问点     static EagerSingleton& getInstance() {         return instance;     } };  // 初始化静态实例 EagerSingleton EagerSingleton::instance;  

要想实现单例,从两个方面入手:1.如何实现禁止构造2个或者2个以上的实例化对象。2.如何实现只构造一个对象
对于前者,我们可以将构造函数私有化,这样就不能在类外部构造对象了。那怎么保证拥有一个实例化对象呢?这一点可以在类中使用static修饰一个该类的实例对象,这样就能在程序加载的时候自动创建一个实例化对象,由于static成员属于类本身的特性,所以能使用私有的构造函数,且只会加载一次。

要想使用这个单例,就需要一个static修饰的成员方法专门用来提供全局的访问点,因为static成员函数可以直接通过类名使用,不需要创建实例化对象。 此外静态成员变量需要在类外部初始化

饿汉实现模式的特点

  • 类加载的时候实例化
  • 私有化构造函数
  • 线程安全由于实例化是在类加载的时候完成的,且类加载的过程中由C++标准保证了线程安全,因此不需要额外的同步机制来保证线程安全。

懒汉实现方式

观察下面代码

class LazySingleton { private:     // 私有的静态指针变量,用于指向唯一的实例     static LazySingleton* instance;      // 私有构造函数,防止外部实例化     LazySingleton() {}  public:     // 提供全局访问点     static LazySingleton* getInstance() {         if (instance == nullptr) {             instance = new LazySingleton();         }         return instance;     } };  // 初始化静态指针变量 LazySingleton* LazySingleton::instance = nullptr;  

注意其中和饿汉实现方式的区别,懒汉实现单例模式中static修饰的是一个实例对象的指针。这样一来,类加载的时候就不会构造自动一个实例化对象。具体的观察这一段代码:

static LazySingleton* getInstance() {         if (instance == nullptr) {             instance = new LazySingleton();         }         return instance;     } 

这一段代码保证了该类只能实例化对象一次,且只在第一次调用getInstance() 函数时才会创建。这样一来也能实现单例模式。但是和饿汉模式不一样的是,这种单例模式只在第一次使用的时候实例化一个对象,而饿汉模式是程序开始时不管你用不用都会实例化一个。这种机制又被称为延迟实例化机制。此外,这种机制在多线程模式下是不安全的。比如可能会有多个线程
new LazySingleton();
为了保证线程安全,我们需要使用锁来保证创建实例化对象时同步。例如下面代码:

#include   class LazySingleton { private:     static LazySingleton* instance;     static std::mutex mtx;     LazySingleton() {}  public:     static LazySingleton* getInstance() {         std::lock_guard lock(mtx);         if (instance == nullptr) {             instance = new LazySingleton();         }         return instance;     } };  // 初始化静态变量 LazySingleton* LazySingleton::instance = nullptr; std::mutex LazySingleton::mtx; 

上面加锁方式在每次调用getInstance()这个函数的时候都会加一次锁,频繁的调用该函数可能会造成一定的性能问题。
对于上面加锁方式还可以进一步进行优化,例如采用双重检查锁定,具体优化的代码如下:

#include   class LazySingleton { private:     static LazySingleton* instance;     static std::mutex mtx;     LazySingleton() {}  public:     static LazySingleton* getInstance() {         if (instance == nullptr) {             std::lock_guard lock(mtx);             if (instance == nullptr) {                 instance = new LazySingleton();             }         }         return instance;     } };  // 初始化静态变量 LazySingleton* LazySingleton::instance = nullptr; std::mutex LazySingleton::mtx;  

这样一来,只有在首次创建对象时会上锁,其余时候都不会也不需要。

懒汉实现方式的特点

  • 线程不安全
  • 延迟实例化
  • 需要使用互斥锁保证线程安全
    具体原因分析上面已经阐述过了,这里就不做过多分析了。

相关内容

热门资讯

有玩家发现!凑一桌辅助器怎么安... 有玩家发现!凑一桌辅助器怎么安装,微乐兰州麻将小程序辅助(本来是真的挂)-哔哩哔哩1、微乐兰州麻将小...
这一现象值得深思!微信小程序中... 这一现象值得深思!微信小程序中至上饶510k辅助器,点我休闲辅助器(其实是有脚本)-哔哩哔哩微信小程...
经调查!花花生活圈辅助,功夫川... 经调查!花花生活圈辅助,功夫川麻老是输什么情况(切实真的是有下载)-哔哩哔哩功夫川麻老是输什么情况辅...
日前!亲友圈辅助吧,牵手app... 日前!亲友圈辅助吧,牵手app破解(本来真的有下载)-哔哩哔哩1、下载好亲友圈辅助吧脚本下载之后点击...
反观!开心庄园脚本辅助器,长城... 反观!开心庄园脚本辅助器,长城互娱辅助(竟然是有app)-哔哩哔哩1、玩家可以在开心庄园脚本辅助器透...
更值得关注的是!大巴杭州辅助,... 更值得关注的是!大巴杭州辅助,纳祥游戏科技(确实真的有挂)-哔哩哔哩该软件可以轻松地帮助玩家将纳祥游...
今天上午!同乡游辅助软件下载,... 今天上午!同乡游辅助软件下载,微信小程序免费黑科技(确实真的是有app)-哔哩哔哩微信小程序免费黑科...
据目击者称!江湖悠悠手游多开辅... 据目击者称!江湖悠悠手游多开辅助,美猴王大厅怎么修改数据(真是是真的插件)-哔哩哔哩1、每一步都需要...
日前!都莱大菠萝辅助,川娱竞技... 日前!都莱大菠萝辅助,川娱竞技插件(切实是有脚本)-哔哩哔哩1、很好的工具软件,可以解锁游戏的都莱大...
长期以来!菜鸟黑桃a3作z弊,... 您好,江西中至小程序黑科技这款游戏可以开挂的,确实是有挂的,需要了解加去威信【136704302】很...