单例模式是一种设计模式.
单例模式表示在定义的某一个类中,只能有唯一的一个对象(即只能有一个实例).
优点:提高了封装性,外部不能轻易的改变实例.
饿汉模式
含义:程序启动后就会立即加载到内存.
缺点:启动比较慢.
代码如下:
#include <iostream>
using namespace std;
template<class T>
class Singleton
{
public:
static T* GetSingleton()
{
return &value;
}
private:
static T value;
};
template<class T>
T Singleton<T>::value = T();
int main()
{
Singleton<int>::GetSingleton();
return 0;
}
懒汉模式
含义:启动的时候不加载,只有当使用的时候才会加载到内存.
#include <iostream>
using namespace std;
//懒汉模式
template<class T> //类模板
class singleton
{
public:
static T* GetSingleton()
{
if(value == NULL)
{
value = new T();
}
return value;
}
private:
static T* value;
};
template<class T>
T* singleton<T>::value = NULL;
int main()
{
singleton<int>::GetSingleton();
return 0;
}
上面这个代码存在一个很重要的问题:
1.如果在多线程的环境下,在函数GetSingleton()中如果进行判断时如果同时多个线程频繁的进行判断,那么就会存在线程安全问题,如果多个线程都判断为空那么就会new出来很多对象,那么明显就是不安全的. 解决:加锁,在判断前进行加锁,在出了if判断再进行解锁. 问题:如果有多个进程频繁的获取锁,然后再进行判断,然后再释放.那么效率就会下降,加锁和解锁也是一种消耗. 解决:在加锁前再进行一次判断,如果为空才进行进行加锁.这样就会大大减少了加解锁的消耗. |
具体的代码如下:
template<class T>
class singleton
{
public:
static T* GetSingleton()
{
if(value == NULL) //这样就只有为空才会进来进行加锁解锁(这样就不会频繁获取锁)
{
lock(); //这是一句伪代码(加锁)
//如果在这儿加锁,所有的线程到这儿都会先加锁(这也是一种消耗),再判断,这样就会造成效率低.所以在这儿之前再进行一次判断
//但是在这儿加锁也会满足线程安全
if(value == NULL)
{
value = new T();
}
unlock(); //伪代码(解锁)
}
return value;
}
private:
static volatile T* value; //加上volatile为了防止编译器过度优化
};
template<class T>
volatile T* singleton<T>::value = NULL;