- 实例初始化简单且轻量,且在整个程序运行周期内始终被使用。
- 需要保证线程安全,但又不想在每次访问时都进行加锁操作。
2. 懒汉模式 (Lazy Initialization)
懒汉模式下,单例实例在首次被请求时才被创建。
// 懒汉模式的单例类
class SingletonLazy {
public:
// 获取唯一实例的静态方法
static SingletonLazy& getInstance() {
// 使用双检锁确保线程安全
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex); // 加锁
if (instance == nullptr) {
instance = new SingletonLazy();
}
}
return *instance;
}
// 禁止拷贝构造和赋值运算符
SingletonLazy(const SingletonLazy&) = delete;
SingletonLazy& operator=(const SingletonLazy&) = delete;
private:
// 私有静态成员变量指针,初始化为nullptr
static SingletonLazy* instance;
static std::mutex mutex; // 用于保证线程安全的互斥量
// 私有构造函数,确保无法从外部创建新实例
SingletonLazy() {}
};
// 静态成员变量初始化
SingletonLazy* SingletonLazy::instance = nullptr;
std::mutex SingletonLazy::mutex;
特点和适用场景:
- 延迟加载: 懒汉模式仅在需要时才创建实例,节省了资源和初始化时间。
- 线程安全性: 使用双检锁(double-checked locking)确保在多线程环境下仍能保持高效和线程安全。
- 资源消耗: 首次访问时的初始化开销可能会影响性能,特别是在高并发环境中。
适用场景:
- 实例初始化开销较大,不一定在程序运行的每个阶段都被用到。
- 需要延迟加载以节省资源,或者在实例初始化时有复杂的逻辑处理。
使用单例模式的示例:
int main() {
// 使用饿汉模式获取单例实例
SingletonEager& instance1 = SingletonEager::getInstance();
// 使用懒汉模式获取单例实例
SingletonLazy& instance2 = SingletonLazy::getInstance();
return 0;
}
在实际应用中,根据具体的需求和性能要求选择合适的单例模式实现。饿汉模式适合于实例初始化开销较小且始终会被使用的情况,而懒汉模式则适用于实例初始化开销较大或可能不被使用的情况。