[4] [对象性能] ( 1 ) 单例模式 Singleton

总结

  • 场景
    资源分享(数据库)
    配置管理
    日志管理
    对象工厂




c++例子

  • 经典的magic static版本 (c++11之后才支持)
    (这个版本是线程安全的, 原因是其他线程会等到第一个线程完成instance的构建)
    更多参考:
    https://zhuanlan.zhihu.com/p/344714248

#include <iostream>

class Singleton {
public:
    static Singleton &getInstance() {
        // 在首次调用时进行初始化,且线程安全
        static Singleton instance;
        return instance;
    }

    Singleton(const Singleton &) = delete;

    void operator=(const Singleton &) = delete;

    void doSomething() {
        std::cout << "Singleton instance is doing something." << std::endl;
    }

private:
    Singleton() = default;
};

int main() {
    Singleton &instance1 = Singleton::getInstance();
    instance1.doSomething();

    // 尝试实例化第二个对象,实际上该对象和第一个是同一个
    Singleton &instance2 = Singleton::getInstance();
    instance2.doSomething();

    // 编译器将阻止下面的行,因为复制构造函数和赋值操作符重载已被删除
    // Singleton instance3 = instance1;
    // Singleton instance4;
    // instance4 = instance1;
    return 0;
}





  • 线程安全版本
    锁的代价过高, 不推荐
Singleton* Singleton::getInstance() {
    Lock lock;
    if (m_instance == nullptr) {
        m_instance = new Singleton();
    }
    return m_instance;
}





  • 双检查锁版本
    编译器存在reorder行为,
    这个版本的内存读写不安全.
Singleton* Singleton::getInstance() {
    
    if(m_instance==nullptr){
        Lock lock;
        if (m_instance == nullptr) {
            m_instance = new Singleton();
        }
    }
    return m_instance;
}





  • 用atomic实现正确的双检查锁单例模式
#include <iostream>
#include <atomic>
#include <mutex>

class Singleton {
public:
    // 获取单例实例的静态方法
    static Singleton *getInstance() {
        Singleton *temp = instance.load(std::memory_order_relaxed);

        // 创建一个内存屏障, 确保在屏障之前对变量temp的读取操作, 不会被移到屏障之后.
        std::atomic_thread_fence(std::memory_order_acquire);

        // 双重检查锁定模式(double-checked locking pattern) 确保多线程创建单例对象的安全性
        if (temp == nullptr) {
            std::lock_guard<std::mutex> lock(mutex);

            // 读取
            temp = instance.load(std::memory_order_relaxed);
            if (temp == nullptr) {
                temp = new Singleton();

                // 释放内存屏障
                std::atomic_thread_fence(std::memory_order_release);

                // 写入
                instance.store(temp, std::memory_order_relaxed);

                std::cout << "new singleton instance." << std::endl;
            }
        }
        return temp;
    }

    // 删除拷贝构造函数和赋值操作符重载,以确保单例类不会被复制
    Singleton(const Singleton &) = delete;

    void operator=(const Singleton &) = delete;

    // 释放单例对象
    static void destroyInstance() {
        Singleton *temp = instance.load();
        if (temp != nullptr) {
            // Lock to prevent multiple threads from concurrently destroying the instance
            std::lock_guard<std::mutex> lock(mutex);
            // Set the instance pointer to nullptr and get the previous value
            temp = instance.exchange(nullptr);
            if (temp != nullptr) {
                delete temp;
                std::cout << "delete singleton instance." << std::endl;
            }
        }
    }

    // 其他成员函数和成员变量
    void doSomething() {
        std::cout << "Singleton instance is doing something." << std::endl;
    }

private:
    // 将默认构造函数设为私有,防止外部类实例化该类
    Singleton() = default;

    // 使用 std::atomic 来保证线程安全和避免重排序
    static std::atomic<Singleton *> instance;
    static std::mutex mutex;
};

// 在类外初始化静态成员
std::atomic<Singleton *> Singleton::instance(nullptr);
std::mutex Singleton::mutex;

int main() {
    Singleton *instance1 = Singleton::getInstance();
    instance1->doSomething();

    Singleton *instance2 = Singleton::getInstance();
    instance2->doSomething();

    printf("%p, %p \n",
           static_cast<void *>(instance1), static_cast<void *>(instance2));

    instance1->destroyInstance();
    instance2->destroyInstance();
    return 0;
}





java例子1

未完成...










posted @ 2023-11-25 02:21  qwertzxc  阅读(15)  评论(0)    收藏  举报