单例模式---线程安全实现

文章目录

1.单例模式的特点😊

1.全局只有一个类的static实例存在;

2.不允许直接实例化,构造函数为私有的,只通过一个类的静态方法获取该实例;

2.单例模式两种实现🤣🤗😊

2.1 饿汉式

饿汉式是在类加载的时候就会创造实例,会造成资源的浪费。 具体:内部先定义并初始化好了一个静态实例。获取方法中直接返回实例。

特点:线程安全,会造成资源浪费

实现:

cpp 复制代码
class Singleton {
private:
    static Singleton instance;

    // 私有构造函数,防止类外实例化对象
    Singleton() {}

public:
    // 获取实例的静态方法
    static Singleton& getInstance() {
        return instance;
    }

    // 其他成员函数
    void doSomething() {
        // do something
    }
};

// 静态成员变量需要在类外初始化
Singleton Singleton::instance;

int main() {
    // 获取单例对象实例
    Singleton& singleton = Singleton::getInstance();
    // 调用单例对象的方法
    singleton.doSomething();

    return 0;
}

2.2 懒汉式

懒汉式是在需要时才创建实例,通过获取实例方法获取实例。

具体:内部定义一个静态实例,获取方法中判断实例是否为空,空则初始化实例;否则返回该实例

特点:避免资源浪费,造成线程安全问题。

实现

cpp 复制代码
class Singleton {
private:
    // 静态成员变量,用于保存单例实例
    static Singleton* instance;
    
    // 构造函数私有化,防止外部创建实例
    Singleton() {}
    
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;  // 初始化静态成员变量

int main() {
    // 获取单例实例
    Singleton* singleton1 = Singleton::getInstance();
    Singleton* singleton2 = Singleton::getInstance();
    
    // 判断两个实例是否相同
    if (singleton1 == singleton2) {
        cout << "两个实例相同" << endl;
    } else {
        cout << "两个实例不相同" << endl;
    }
    
    return 0;
}

3.传统单例模式的线程安全问题

饿汉式是线程安全的,懒汉式不是

当多线程执行getInstance时候,如果线程A判断当前实例为空,线程B正好判断到也为空,就会申请资源;当线程A恢复了后,继续执行,也会申请内存空间;就会出现两个实例,这就会出现问题;

4.解决方法

4.1静态局部变量

cpp 复制代码
class Singleton {
private:
    Singleton() {}
    
public:
    static Singleton* getInstance() {
        static Singleton instance;
        return &instance;
    }
};

4.2加锁

cpp 复制代码
class Singleton {
private:
    // 静态成员变量,用于保存单例实例
    static Singleton* instance;
    
    // 构造函数私有化,防止外部创建实例
    Singleton() {}
    
public:
    // 静态成员函数,用于获取单例实例
    static Singleton* getInstance() {
        // 判断实例是否为空,如果为空则创建实例
        Mutexlock lock(mutex);//加锁
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
    
    // 删除拷贝构造函数和拷贝赋值运算符,防止被复制
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance = nullptr;  // 初始化静态成员变量

int main() {
    // 获取单例实例
    Singleton* singleton1 = Singleton::getInstance();
    Singleton* singleton2 = Singleton::getInstance();
    
    // 判断两个实例是否相同
    if (singleton1 == singleton2) {
        cout << "两个实例相同" << endl;
    } else {
        cout << "两个实例不相同" << endl;
    }
    
    return 0;
}

4.3双重检查锁(DCL)

cpp 复制代码
class Singleton {
private:
    // 静态成员变量,用于保存单例实例
    static Singleton* instance;
    
    // 构造函数私有化,防止外部创建实例
    Singleton() {}
    
public:
    // 静态成员函数,用于获取单例实例
    static Singleton* getInstance() {
        // 判断实例是否为空,如果为空则创建实例
        if (instance == nullptr) {
        Mutexlock lock(mutex);
        if(instance==nullptr)
            instance = new Singleton();
        }
        return instance;
    }
    
    // 删除拷贝构造函数和拷贝赋值运算符,防止被复制
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

Singleton* Singleton::instance = nullptr;  // 初始化静态成员变量

int main() {
    // 获取单例实例
    Singleton* singleton1 = Singleton::getInstance();
    Singleton* singleton2 = Singleton::getInstance();
    
    // 判断两个实例是否相同
    if (singleton1 == singleton2) {
        cout << "两个实例相同" << endl;
    } else {
        cout << "两个实例不相同" << endl;
    }
    
    return 0;
}

4.4pthread_once

cpp 复制代码
#include<iostream>
class singleton{
public:
static singleton& getinstance()
{
pthread_once(&ponce,init);//保证该函数只被执行一次
return instance;
}
private:
static void init()
{
instance=new singleton();
}
singleton(){}
~singleton(){}
static pthread_once_t  ponce;
static singleton* instance;
};
singleton::ponce=PTHREAD_ONCE_INIT;
singleton::instance=nullptr;
相关推荐
Ayanami_Reii几秒前
区间不同数的个数-树状数组/线段树/莫队/主席树
数据结构·c++·算法·线段树·树状数组·主席树·莫队
大筒木老辈子16 分钟前
C++笔记---并发支持库(atomic)
java·c++·笔记
zero_hz18 分钟前
核心区分:用户态/内核态切换 vs. 程序阻塞
c++·io·内核态用户态
胡萝卜3.018 分钟前
深入C++可调用对象:从function包装到bind参数适配的技术实现
开发语言·c++·人工智能·机器学习·bind·function·包装器
CoderYanger32 分钟前
C.滑动窗口-求子数组个数-越长越合法——3325. 字符至少出现 K 次的子字符串 I
c语言·数据结构·算法·leetcode·职场和发展·哈希算法·散列表
看见繁华41 分钟前
C++ 高级
开发语言·c++
点灯master1 小时前
DAC8562的驱动设计开发
c语言·驱动开发·stm32
点云SLAM1 小时前
constexpr 和 explicit 在 C++ 中被提出的动机
开发语言·c++·explicit关键字·隐式转换·constexpr关键字·c++11/17/20
冷崖1 小时前
工厂模式-创建型
c++·设计模式
qq_310658511 小时前
mediasoup源码走读(六)——NetEQ
服务器·c++·音视频