线程安全的单例模式
单例模式
- 单例模式:非常典型的一种设计模式
- 应用场景:一个类型只能实例化一个对象,一份资源只能被加载一次
实现:饿汉方式/懒汉方式
- 饿汉方式:资源在程序初始化阶段就完成加载(以空间换时间)
- 懒汉方式:资源在使用的时候再加载(延迟加载,节省资源)
饿汉方式
- 静态修饰资源,保证资源只有一份,并且在程序初始化阶段完成加载
- 构造函数私有化,一个类只能实例化一个对象
- 不需要考虑线程安全问题
- 提供统一接口进行返回
//不需要考虑线程安全问题
template<class T>
class Singleton
{
public:
T *GetInstance()
{
return &_data;
}
private:
static T _data; //静态修饰资源,保证资源只有一份,并且在程序初始化阶段完成加载
Singleton(){}//构造函数私有化,一个类只能实例化一个对象
};
懒汉方式
- 延迟加载
- 构造函数私有化
- 定义对象指针、static修饰(类中资源对象使用指针,并且使用static进行修饰)
- 资源指针使用volatile修饰(防止过度优化)
- 提供统一接口进行访问 --若资源未加载则进行实例化加载
- 加锁保护资源加载过程–线程安全
- 外部二次检测–提高效率
template<class T>
class Singleton
{
private:
//Singleton(){}//构造函数私有化,一个类只能实例化一个对象
volatile static T *_data; //定义对象指针,volatile防止编译器过度优化
static std::mutex _mutex; //静态修饰,保证访问的是同一个
public:
static T* GetInstance()
{
if(_data == NULL) //二次检测--提高效率
{
_mutex.lock(); //加锁保护--线程安全
if(_data == NULL)
{
_data = new T();
}
_mutex.unlock();
]
return _data;
}
}
- STL中的容器都是非线程安全的
- 智能指针都是线程安全的,或者说大部分都不涉及线程安全问题