线程安全的单例模式
什么是单例模式
上一节把线程池封装起来之后,新的问题就出来了:如果同一套线程池被创建成多个对象,每个对象又各自拉起一批线程,资源很快就会被吃光。这个场景里,单例模式就不是'设计得优雅',而是'别让系统自己把自己拖垮'。
单例模式的特点
有些类在一个进程里就只需要一个实例,比如管理大块共享数据、统一调度线程池、维护全局状态的对象。对象多了,反而麻烦;一个就够了。
饿汉模式和懒汉模式
饿汉和懒汉很好理解。
吃完饭马上洗碗,下一顿直接用,这是饿汉。
吃完饭先放着,等下一顿真要用了再洗,这是懒汉。
饿汉模式实现
只要通过 Singleton 这个包装类访问 T,进程里就只会有一个 T 的实例。
template <typename T> class Singleton {
static T data;
public:
static T* GetInstance() { return &data; }
};
这里的 static 变量会在程序启动时就完成初始化。站在进程角度看,它不是'临时申请出来再管理',而是直接放进全局数据区,加载阶段就准备好了。没等你用,它已经存在了。
这也是它'饿汉'的地方:先占位,再说。
为什么它天然就是单例?原因很朴素:
- 全局只有一份静态对象
- 禁掉拷贝构造和赋值后,外面也很难再复制出第二份
懒汉模式实现
懒汉模式是延迟创建。对象不用的时候不占资源,真正要用时才创建。
// 懒汉模式,线程安全
template <typename T> class Singleton {
volatile static T* inst; // 需要设置 volatile 关键字,否则可能被编译器优化。
static std::mutex lock;
public:
static T* GetInstance() {
if (inst == NULL) {
// 双重判定空指针,降低锁冲突的概率,提高性能。
lock.lock();
(inst == ) {
inst = ();
}
lock.();
}
inst;
}
};









