什么是单例模式?
单例模式,顾名思义就是一个类只能实例化产生一个对象,并提供一个访问它的全局访问点,该实例被所有程序模块共享。
单例模式的应用场景?
在设计或开发中,肯定会有这么一种情况,一个类只能有一个对象被创建,如果有多个对象的话,可能会导致状态的混乱和不一致。这种情况下,单例模式是最恰当的解决办法。它有很多种实现方式,各自的特性不相同,使用的情形也不相同。
单例模式的要点?
- 确保一个类只有一个实例被建立
- 提供了一个对对象的全局访问指针
- 自己向整个系统提供提供这个实例
普通懒汉模式(非线程安全)
懒汉式的特点是延迟加载,比如配置文件,采用懒汉式的方法,顾名思义,懒汉嘛,很懒的,当第一次使用时才创建一个唯一的实例对象,从而实现延迟加载的效果。
class Singleton
{
private:
static Singleton *singleton;
Singleton() //构造函数私有化 防止外部私自创建对象
{
cout << "Singleton()" << endl;
}
public:
static Singleton* Get_Instance()
{
if (singleton == NULL)//判断对象是否已经存在
{
singleton = new Singleton();
}
return singleton;
}
//利用静态变量在程序结束会自动释放的特点
//定义一个嵌套类专门用来释放单例对象
class Destroy
{
public:
~Destroy()
{
if (Singleton::singleton)
{
delete Singleton::singleton;
cout << "~CSingleton()" << endl;
}
}
};
static Destroy destroy;
};
//懒汉模式定义类时不创建唯一的类对象
//而是当使用的时候才唯一创建该单例的唯一对象
//所以初始化为NULL;
Singleton* Singleton::singleton = NULL;
Singleton::Destroy destroy;
int main()
{
cout << "process start!" << endl;
Singleton* s1 = Singleton::Get_Instance();
Singleton* s2 = Singleton::Get_Instance();
cout << s1 << endl;
cout << s2 << endl;
}
运行结果如下:
由运行结果可以看出:程序运行起来之后实例化s1的时候才进行的单例对象的构造,确实是懒汉模式的特点:第一次使用的时候才进行创建唯一的单例对象。实例化s2产生的对象是同一个对象,达到了懒汉模式的期望
普通懒汉模式的缺点
这个实现在单线程下是正确的,但在多线程情况下,如果两个线程同时首次调用Get_Instance方法且同时检测到singleton是NULL,则两个线程会同时构造一个实例给singleton,这样就会发生错误,违背了单例模式最初的思想。
线程安全的懒汉模式(双重检查锁)
思路:因为加锁是一个非常耗时的操作,所以只有在第一次创建对象的时候进行加锁,当Instance不为空即对象已经存在的时候就不需要进行加锁的操作。
注意:如果没有添加pthread的库文件的话需要先添加库文件,vs编译器下在项目–>管理NuGet程序版中搜索pthread进行添加;
我找了一个博客写按照他的方法操作下来没有一点问题,完美运行,附上博客链接
https://blog.youkuaiyun.com/qianchenglenger/article/details/16907821?tdsourcetag=s_pctim_aiomsg
代码如下:
#include<iostream>
#include<pthread.h>
using namespace std;
#pragma comment(lib,"x86/pthreadVC2.lib")
class Singleton
{
private:
static Singleton *singleton;
Singleton()
{
cout << "Singleton()" << endl;
}
public:
static pthread_mutex_t mutex; //定义锁变量
static Singleton* Get_Instance()
{
if (singleton == NULL)
//先判断单例对象是否已经产生
//若已经产生就不用进行加锁解锁操作直接返回对象的指针
{
pthread_mutex_lock(&mutex);
cout << "ADDLOCK()" << endl;
if (singleton == NULL)
{
singleton = new Singleton();
}
pthread_mutex_unlock(&mutex);
cout << "UNLOCK()" << endl;
}
return singleton;
}
class Destroy
{
public:
~Destroy()
{
if (Singleton::singleton)
{
delete Singleton::singleton;
cout << "~CSingleton()" << endl;
}
}
};
static Destroy destroy;
};
Singleton* Singleton::singleton = NULL;
Singleton::Destroy destroy;
pthread_mutex_t Singleton::mutex = PTHREAD_MUTEX_INITIALIZER;//静态初始化锁变量
int main()
{
cout << "process start!" << endl;
Singleton* s1 = Singleton::Get_Instance();
Singleton* s2 = Singleton::Get_Instance();
cout << s1 << endl;
cout << s2 << endl;
}
运行结果如下
饿汉模式(线程安全)
饿汉式的特点是一开始就加载了,如果说懒汉式是“时间换空间”,那么饿汉式就是“空间换时间”,因为一开始就创建了实例,所以每次用到的时候直接返回就好了。
class Singleton
{
private:
static Singleton *singleton;
Singleton()
{
cout << "Singleton()" << endl;
}
public:
static Singleton* Get_Instance()
{
return singleton;
}
class Destroy
{
public:
~Destroy()
{
if (Singleton::singleton)
{
delete Singleton::singleton;
cout << "~CSingleton()" << endl;
}
}
};
static Destroy destroy;
};
//饿汉模式定义类时直接创建唯一的单例对象
Singleton* Singleton::singleton = new Singleton();
Singleton::Destroy destroy;
int main()
{
cout << "process start!" << endl;
Singleton* s1 = Singleton::Get_Instance();
Singleton* s2 = Singleton::Get_Instance();
cout << s1 << endl;
cout << s2 << endl;
}
由运行结果可以看出:在程序没有开始运行时就已经产生了唯一的实例化对象 而实例化s1的时候唯一的单例对象已经存在,这时候只是在调用该已经存在的单例对象,确实是饿汉模式的特点:定义类的时候就已经实例化产生了该单例模式的唯一的对象,而后面使用的时候只是调用该单例对象。达到了饿汉模式的期望.