单例模式
单例模式:是非常典型常用的一种设计模式
一份资源只能被申请加载一次/单例模式的方法创建的类在当前进程中只有一个实例
实现单例模式
饿汉方式
资源的程序初始化的时候就去加载,后面使用的时候直接使用,使用的时候比较流畅,有可能会加载用不上的资源,导致程序初始化时间比较慢。
#include <cstdio>
class single_instance
{
public:
int * get_instance(){
return &_data;
}
private:
static int _data;
};
int single_instance::_data = 10;//静态成员变量需要在类外初始化
int main()
{
single_instance a1;
single_instance b1;
printf("a1:%d-%p\n", *(a1.get_instance()), a1.get_instance());
printf("b1:%d-%p\n", *(b1.get_instance()), b1.get_instance());
}
懒汉模式
资源在使用的时候发现还没加载,则申请加载
初始化比较快,第一次运行某个模块的时候比较慢,因为需要加载资源
#include <cstdio>
#include <thread>
#include <mutex>
std::mutex g_mutex;
class single_instance
{
public:
volatile int *get_instance() {
//不管——data资源是否已经被加载,每次都要加锁判断,然后解锁
//若资源已经加载过了,加锁解锁就有点浪费资源,并且容易造成锁冲突
//4. 二次判断,避免每次都会加锁解锁
if (_data == NULL) {
//-----------------//
g_mutex.lock();//3. 实现线程安全
if (_data == NULL) {
_data = new int;
*_data = 10;
}
g_mutex.unlock();
}
return _data;
}
private:
//1. static 保证所有对象使用同一份资源
//2. volatile 防止编译器过度优化
volatile static int *_data;
};
volatile int *single_instance::_data = NULL;
int main()
{
single_instance a1;
single_instance b1;
printf("a1:%d-%p\n", *(a1.get_instance()), a1.get_instance());
printf("b1:%d-%p\n", *(b1.get_instance()), b1.get_instance());
}
注意事项:
- 使用static保证所有对象使用同一份资源
- 使用volatile,防止编译器过度优化
- 实现线程安全,保证资源判断以及申请过程是安全的
- 外部二次判断,以及避免资源已经加载成功每次获取都需要加锁解锁,以及带来的锁冲突