单例模式的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中 一个类只有一个实例,即一个类只有一个对象实例。
单例模式要求相应的类,只需要构造对象一次就行了。
因此需要将这个类的构造方法改为私有
所有类有构造方法,不编码则系统默认生成空的构造方法,若有显示定义的构造方法,默认的构造方法就会失败。
这样对外部代码,不能用new来实例化它,但是我们完全可以再写一个public方法
单例模式:客户端不再需要考虑是否需要去实例化的问题,而把责任都给了应该负责的类去处理。
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
版本一:使用懒加载(快加载),只有在使用时才实例化
class Singleton
{
public:
static Singleton* getIntance()
{
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pobject = new Singleton();
}
return pobject;
} private:
Singleton(){}
static Singleton *pobject;
};
Singleton* Singleton::pobject = NULL;//懒加载,只有在使用时才生成
版本二:考虑多线程安全问题,使用互斥锁
判断是否是线程安全的——是否存在竞态条件 判断是否存在竞态条件。
随着线程调度顺序的不同,代码执行的结果也会不同。
存在竞态条件的代码称为临界区,临界区代码需要是原子操作,实现原子操作需要使用 互斥锁,if 语句不是原子操作
class Singleton
{
public:
static Singleton* getIntance()
{
pthread_mutex_lock(&mutex);//多线程线程安全问题
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pobject = new Singleton();
}
pthread_mutex_lock(&mutex);
return pobject;
}
private:
Singleton(){}
static Singleton *pobject;
};
Singleton* Singleton::pobject = NULL;//快加载 懒加载
版本三:由于可能存在单线程或多线程共存的使用场景,降低单线程获取释放锁的效率,使 用双重 if 判断
单线程时,只需要执行一次获取释放互斥锁操作,之后第一个 if 语句都为 false 多线程时,依旧考虑线程安全与竞态条件问题
class Singleton
{
public:
static Singleton* getIntance()
{
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pthread_mutex_lock(&mutex);//多线程线程安全问题 //多线程线程安全问题
if (pobject == NULL)//单线程时效率问题
{
pobject = new Singleton();
}
pthread_mutex_lock(&mutex);//多线程线程安全问题
}
return pobject;
}
private:
Singleton(){}
static Singleton *pobject;
};
Singleton* Singleton::pobject = NULL;//快加载 懒加载
版本四:考虑编译器的指令优化和 CPU 的动态指令优化
volatile 关键字阻止编译器为了提高速度将一个变量缓存到寄存器内而不写回内存 volatile 关键字阻止编译器调整操作
volatile 变量的指令操作 barrier 指令会阻止 CPU 对指令进行动态换序优化
class Singleton
{
public:
volatile static Singleton* getIntance()
{
if (pobject == NULL)//懒加载,只有在使用时才生成
{
pthread_mutex_lock(&mutex);//多线程线程安全问题
if (pobject == NULL)//单线程时的效率问题
{
Singleton* temp = new Singleton;
barrier();//防止 CPU 对指令进行动态换序优,使对象的构造一定在 barrier 完成,因此赋值给 pobject 的对象是完好的
pobject = temp;
}
pthread_mutex_lock(&mutex);
}
return pobject;
}
private:
Singleton(){}
volatile static Singleton *pobject;
};
volatile Singleton* Singleton::pobject = NULL;//快加载 懒加载
考点: 考察设计模式的一个常用模式:单例模式