1. 单例设计模式
单例模式,是一种常用的软件设计模式。应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。
具体实现
(1)将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
(2)在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。
(3)定义一个静态方法返回这个唯一对象。
实现一:饿汉式:该模式的特点是类一旦加载就创建一个单例,保证在调用 getInstance 方法之前单例已经存在了(所以,在外面的多线程访问这个接口时,对象只有一个,因此不存在多线程安全问题)。
class Single
{
private:
Single(){}
static Single instance = new Single();
public:
static Single getInstance()
{
return instance;
}
}
实现二:懒汉式:该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。
class Single
{
private:
Singleton(){}
static Single instance = null;
public:
static Single getInstance()
{
if(instance==null)
{
instance = new Single();
}
return instance;
}
}
单例类的获取是通过对外提供的:getInstance()接口,那么多个线程同时调用这个接口时可能会产生多个单例类,因此需要加锁。饿汉式在多线程下是安全的;懒汉式需要加锁,如下:
class Single
{
private:
Singleton(){}
static Single instance = null;
public:
std::mutex mutex;
static Single getInstance()
{
std::lock_guard<std::mutex> lock(mutex);
if(instance==null)
{
instance = new Single();
}
return instance;
}
}
上面加锁的弊端时,使用一次(调用一次getInstance())就要加一次锁。。。真正应该是第一次创建类对象时加锁,如下:
下面的做法:不用让线程每次都加锁,而只是在实例未被创建时再加锁,这种做法称为:Double-Check Locking(双重锁定)
class Single
{
private:
Singleton(){}
static Single instance = null;
public:
std::mutex mutex;
static Single getInstance()
{
if(instance==null)
{
std::lock_guard<std::mutex> lock(mutex);
if(instance==null)
{
instance = new Single();
}
}
return instance;
}
}
第一个条件判断的意思是,某个线程实例化后,其他线程和此线程都不应该再进入了。
那么为什么里面还要再判断一次呢?
第二个条件判断的意思是,第一次实例化时,好几个线程一同进入加锁的位置,如果没有第二个条件,那么就不能避免重复创建类对象(线程1,2,3同时进入第一个if,得到null;然后线程1获得到了锁,线程2,3阻塞;线程1获得锁后,创建了单例对象,并释放了锁;然后线程2获取到了锁,此时线程2中的还为null;所以,如果不加里面的那层if判断,这时线程2又要创建对象了)。
还可以使用:std::call_once()来改造单例类(只被调用一次)
std::once_flag g_flag;
class Single
{
private:
Singleton(){}
static Single instance = null;
static void creatInstance()
{
instance = new Single();
}
public:
static Single getInstance()
{
if(instance==null)
{
//假设两个线程多执行到了这里,其中一个线程要等另一个线程执行完毕
std::call_once(g_flag, CreateInstance);
}
return instance;
}
}