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


    1.单例模式的特点😊

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

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

    2.1 饿汉式

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

    实现:

    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 懒汉式

    懒汉式是在需要时才创建实例,通过获取实例方法获取实例。
    具体:内部定义一个静态实例,获取方法中判断实例是否为空,空则初始化实例;否则返回该实例
    特点:避免资源浪费,造成线程安全问题。
    实现

    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静态局部变量

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

    4.2加锁

    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)

    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

    #include
    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;
    
  • 相关阅读:
    6个可解释AI (XAI)的Python框架推荐
    PyTorch 迭代器读取数据
    android api 34 编译ffmpeg with libfdk-aac
    Java8中List转Map报错“java.lang.IllegalStateException: Duplicate key”
    【2023】Git版本控制-本地仓库详解
    软件测试缺陷报告详解
    java每日一记 —— 第一次研究注解
    自定义MVC框架
    C++学习——前进(三)
    模拟器-雷电-使用adb push或adb pull操作文件
  • 原文地址:https://blog.csdn.net/qq_62821433/article/details/139596028