单例模式:保证一个类只被实例化一次!单例模式有懒汉和饿汉两种模式;
懒汉模式:第一次用到类的时候再去实例化;适合在访问量较小的时候使用;
【时间换空间,懒汉模式本身是线程不安全的!】
饿汉模式:类定义的时候就初始化;由于要进行线程同步,所以在访问量较大或可能访问的线程较多的情况下使用
【空间换时间,安全!】
< 饿汉模式 >
template<class T>
class singleton
{
protected:
sigleton {}; //构造函数
private:
sigleton(const sigleton&) {}; //禁止拷贝
sigleton& operator = (const sigleton&) {}; //禁止赋值
static T* m_instance;
public:
static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
return m_instance;
}
template<class T>
T* sigleton<T>::m_instance = new T();
在实例化m_instance变量的时候,直接调用类的构造函数,在未使用变量的时候,已经对m_instance进行赋值;在多线程情况下肯定是线程安全的,因为不存在多线程实例化的问题;
<懒汉模式>
template<class T>
class singleton
{
protected:
sigleton {}; //构造函数
private:
sigleton(const sigleton&) {}; //禁止拷贝
sigleton& operator = (const sigleton&) {}; //禁止赋值
static T* m_instance;
public:
static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
if(m_instance == NULL)
{
m_instance = new T();
}
return m_instance;
}
template<class T>
T* sigleton<T>::m_instance = NULL;
在懒汉模式下,定义m_instance变量先等于NULL,调用GetInstance()方法时判断是否要赋值,不安全是因为当多个线程同时调用GetInstance()方法的时候,有可能导致多个实例产生,所以为了实现线程安全,必须加锁;
<改进1> 利用互斥锁来达到线程安全,但影响效率
template<class T>
class singleton
{
protected:
sigleton {}; //构造函数
private:
sigleton(const sigleton&) {}; //禁止拷贝
sigleton& operator = (const sigleton&) {}; //禁止赋值
static T* m_instance;
public:
static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
pthread_mutex_lock(&mutex);
if(m_instance == NULL)
{
m_instance = new T();
}
pthread_mutex_unlock(&mutex);
return m_instance;
}
template<class T>
//宏来静态初始化互斥锁
pthread_murex_t sigleton<T>::mutex = PTHREAD_MUTEX_INITIALIZER;
template<class T>
T* sigleton<T>::m_instance = NULL;
每次调用GetInstance()方法进来都要加锁,影响效率!
<改进2> “双检锁”机制,用局部变量过渡
template<class T>
class singleton
{
protected:
sigleton {}; //构造函数
private:
sigleton(const sigleton&) {}; //禁止拷贝
sigleton& operator = (const sigleton&) {}; //禁止赋值
static T* m_instance;
public:
static T* GetInstance();
};
template<class T>
T* sigleton<T>::GetInstance()
{
if(m_instance == NULL)
{
pthread_mutex_lock(&mutex);
if(m_instance == NULL)
{
m_instance = new T();
}
pthread_mutex_unlock(&mutex);
}
return m_instance;
}
template<class T>
T* sigleton<T>::m_instance = NULL;
“双检锁”机制,但是当执行m_instance = new T();时,可能类T还没有完成初始化,m_instance就已经有值了,这样会导致另外一个调用GetInstance()方法的线程获取到还未完成初始化的m_instance指针;