设计模式——单例模式

单例模式

定义

单例模式(Singleton),保证一个类仅有一个实例,并提供了访问它的全局访问点。
“通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象,一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。”

实现方式

class Singleton {
private:
    static Singleton* instance; // 静态实例指针
    Singleton() {}  // 私有构造函数

public:
    // 禁止拷贝构造和赋值操作符
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

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

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

线程安全

当多个线程几乎同时进入 getInstance() 方法,并且 instance 仍然是空指针的情况下。各线程可能会同时发现 instance 是空的,然后各自创建一个新的实例,这就违反了单例模式的唯一实例原则。

例子说明

假设 Singleton::getInstance() 实现如下:

static Singleton* getInstance() {
    if (instance == nullptr) {
        instance = new Singleton();  // 多个线程可能同时执行到这一步
    }
    return instance;
}

在这种情况下,线程A和线程B可能几乎同时进入 getInstance() 方法,且都发现 instance == nullptr,于是它们各自创建了一个 Singleton 实例。这就违背了单例模式的初衷。

解决方案

要在多线程环境中确保单例模式的正确性,必须对实例创建过程进行同步。常用的解决方案包括:

  1. 使用互斥锁(Mutex)
    在创建实例的代码块上使用互斥锁,以确保同一时刻只有一个线程能进入该代码块。虽然有效,但锁可能导致性能下降,特别是在高并发的情况下。
static Singleton* getInstance() {
    std::lock_guard<std::mutex> lock(mutex);  // 锁住代码块
    if (instance == nullptr) {
        instance = new Singleton();
    }
    return instance;
}

private:
static std::mutex mutex;  // 静态互斥锁
  1. 双重检查锁定(Double-Checked Locking)
    为了减少不必要的锁操作,可以使用双重检查锁定。在进入锁定区之前先检查一次 instance,只有在 instance 为空时才加锁进行第二次检查。
static Singleton* getInstance() {
    if (instance == nullptr) {  // 第一次检查
        std::lock_guard<std::mutex> lock(mutex);
        if (instance == nullptr) {  // 第二次检查
            instance = new Singleton();
        }
    }
    return instance;
}
  1. 静态局部变量 (C++11 起支持)
    C++11 引入的静态局部变量的线程安全性可以避免手动加锁。在 C++11 标准中,静态局部变量的初始化是线程安全的,这样可以简化代码:
static Singleton& getInstance() {
    static Singleton instance;  // 静态局部变量,C++11 保证线程安全
    return instance;
}

应用场景

配置管理:应用程序的全局配置类。
日志管理:记录日志的类,确保所有模块使用同一个日志实例。
资源管理:数据库连接池、线程池等资源管理类。

单例模式的优点:

  1. 控制实例数量,节省资源。
  2. 提供全局访问点,易于管理共享资源。

缺点:
可能导致过多的全局状态,影响模块化和测试性。
在多线程环境下,需要额外的同步机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值