饿汉模式和懒汉模式
🧠 一、核心区别概览
| 特性 | 饿汉模式(Eager) | 懒汉模式(Lazy) |
|---|---|---|
| 实例创建时机 | 程序启动时立即创建实例 | 第一次调用时才创建实例 |
| 是否线程安全 | 天然线程安全(静态初始化保证) | 需要手动加锁确保安全 |
| 内存占用 | 提前分配,可能浪费资源 | 按需创建,节省资源 |
| 实现复杂度 | 简单 | 稍复杂(涉及同步) |
| 适用场景 | 实例一定会用到 | 实例可能不会被用到 |
⚙️ 二、饿汉模式(Eager Singleton)
思路:
类加载时就创建实例,确保线程安全,但即使从未使用也会占用内存。
✅ 实现示例:
#include <iostream>
using namespace std;class Singleton {
private:static Singleton instance; // 提前创建好实例Singleton() { cout << "Eager Singleton Created\n"; }public:// 禁止复制与赋值Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton& getInstance() {return instance; // 返回唯一实例}void show() {cout << "Hello from Eager Singleton!" << endl;}
};// 静态成员初始化
Singleton Singleton::instance;int main() {Singleton& s1 = Singleton::getInstance();Singleton& s2 = Singleton::getInstance();cout << "是否为同一实例: " << (&s1 == &s2) << endl;s1.show();return 0;
}
输出:
Eager Singleton Created
是否为同一实例: 1
Hello from Eager Singleton!
✅ 优点:
-
实现简单,天然线程安全
-
程序启动时初始化,无需加锁
⚠️ 缺点:
-
如果实例很大但一直没用到,会浪费内存
-
初始化顺序不易控制
⚙️ 三、懒汉模式(Lazy Singleton)
思路:
实例在第一次使用时才创建。
但要注意多线程环境下的同步问题。
✅ 非线程安全懒汉模式(最简单版本)
#include <iostream>
using namespace std;class Singleton {
private:static Singleton* instance;Singleton() { cout << "Lazy Singleton Created\n"; }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;int main() {Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();cout << "是否为同一实例: " << (s1 == s2) << endl;
}
⚠️ 问题:
多线程下可能同时进入 if (instance == nullptr),产生多个实例。
✅ 线程安全懒汉模式(双重检查锁)
#include <iostream>
#include <mutex>
using namespace std;class Singleton {
private:static Singleton* instance;static mutex mtx;Singleton() { cout << "Thread-Safe Lazy Singleton Created\n"; }public:Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton* getInstance() {if (instance == nullptr) { // 第一次检查lock_guard<mutex> lock(mtx); // 加锁if (instance == nullptr) { // 第二次检查instance = new Singleton();}}return instance;}
};// 初始化静态变量
Singleton* Singleton::instance = nullptr;
mutex Singleton::mtx;int main() {Singleton* s1 = Singleton::getInstance();Singleton* s2 = Singleton::getInstance();cout << "是否为同一实例: " << (s1 == s2) << endl;
}
✅ 优点:
-
按需加载,节省资源
-
双重检查锁保证线程安全
⚠️ 缺点:
-
实现较复杂
-
静态成员销毁时机需谨慎(程序退出时可能导致未释放)
🧭 四、总结对比
| 对比项 | 饿汉模式 | 懒汉模式 |
|---|---|---|
| 创建时机 | 程序启动时 | 首次调用时 |
| 线程安全性 | 天然安全 | 需加锁实现 |
| 性能 | 启动慢,但访问快 | 启动快,但首次调用慢 |
| 内存占用 | 可能浪费资源 | 更加节省内存 |
| 实现难度 | 简单 | 稍复杂 |
| 推荐使用 | 对象轻量、使用频繁 | 对象重量、使用偶尔 |
🧩 五、总结一句话
饿汉模式:启动即建,全程无锁。
懒汉模式:用时才建,双锁防乱。
