设计模式之——单例模式
单例模式
单例模式是一种常用的软件设计模式,其定义是类所实例化的对象只能允许一个实例存在。
单例模式的特点是: ① 构造函数私有化;② 对象只能由类自己创建;③ 提供一个公有的获取对象的 GetInstance()接口。
单例模式的实现方式——饿汉模式
代码实现:
//饿汉模式
class Singleton
{
public:
static Singleton *GetInstance(); //公有的静态成员方法接口,用来获取单例对象
private:
Singleton();
static Singleton *sig;
};
Singleton * Singleton :: sig = new Singleton();
//在编译期,对 sig 指针调用构造函数进行实例化
//程序运行之前对象已经存在,因此,该模式必为线程安全模式
Singleton * Singleton :: GetInstance() //获取对象的唯一接口
{
return sig;
}
饿汉模式特点:对象在第一时间创建,‘饿’ 字可理解为积极的意思,即对象创建的比较积极,是一种空间换时间的方法。且因为程序运行之前对象已经存在,因此,该模式必为线程安全模式。
单例模式的实现方式——饿汉模式
此处给出优化前和优化后的程序代码,以作比较。
优化前代码(线程不安全的模式):
class Singleton
{
public:
static Singleton *GetInstance(); //公有的静态成员方法接口,用来获取单例对象
private:
Singleton();
static Singleton *sig;
};
Singleton * Singleton :: sig = NULL; //将 sig 初始化为 NULL
Singleton * Singleton :: GetInstance()
{
if(sig == NULL) //sig 为空,创建对象
{
sig = new Singleton();
}
return sig;
}
懒汉模式的特点:sig先置为空,当外部对象调用GetInstance()方法时,对象才开始创建;不安全的原因是:
当多个线程同时调用GetInstance()时,可能会导致产生多个实例,违背了单例模式唯一实例的原则。
优化后代码(线程安全的模式):
//懒汉模式(线程安全)
class Singleton
{
public:
static Singleton *GetInstance(); //公有的静态成员方法接口,用来获取单例对象
private:
Singleton();
static Singleton *sig;
};
Singleton * Singleton :: sig = NULL; //将 sig 初始化为 NULL
Singleton * Singleton :: GetInstance()
{
if(sig == NULL) //sig 为空,创建对象,且后续操作为原子操作
{
pthread_mutex_lock(&mutex); //优化①
if(sig == NULL) //优化②
{
Singleton *tmp = new Singleton(); //优化③
sig = tmp;
}
pthread_mutex_unlock(&mutex); //解锁
}
return sig;
}
线程安全代码的三个优化:
优化① : 加锁,保证后续为原子操作
优化② :此处多了一重对sig的判断,是防止在上述加锁期间,其他线程已经实例化了对象
优化③ :用临时量接受对象,再赋值给sig,是为了防止对象还没有生成,但 sig 却不为空,此时处于一种半实例化状态,其他线程此时调用获取的是一个半实例化对象,因此用临时量确保对象完全实例化。