目录
单例模式简介
单例模式的典型疑问与优缺点:饿汉、懒汉与多线程安全
单例模式的扩展与应用-缓存
单例模式简介
每次程序运行都要读config.ini,由生成的对象传入参数,但计算机读取IO缓慢,而且这些配置基本不会变化,如果每次运行程序都要重新new这个对象,会带来很多不必要的损耗。
那么就需要整个程序运行中有且只有一个全局的对象,这个需求点就是单例模式。
#include
#include
using namespace std;
//外部程序没有机会new这个class
class Singleton {
private:
Singleton() {
m_singer = nullptr;
cout << "构造一个SIngleton" << endl;
}
public:
static Singleton* getInstance() {
if (m_singer == nullptr) {
m_singer = new Singleton;
}
return m_singer;
}
private:
static Singleton* m_singer;
};
Singleton* Singleton::m_singer = nullptr;//懒汉式:延迟加载
//Singleton* Singleton::m_singer = new Singleton;//饿汉式
//C++中构造函数是线程不安全的
int main() {
Singleton* p1 = Singleton::getInstance();
Singleton* p2 = Singleton::getInstance();
printf("%x,%x", p1, p2);
return 0;
}
单例模式的典型疑问与优缺点:饿汉、懒汉与多线程安全
上面的例子就是懒汉式单例。
但是如果这个单例是多线程,会出现什么问题?
假设线程1在运行到m_singer=null时时间片轮转完了,那么此时就会切换到线程2中。
此时线程2也会进入到m_singer=null 这个if语句块中,并创建一个Singleton。
此时线程2结束,切回线程1,线程1继续执行刚才的现场,又创建了一个Singleton!
那么如何解决这个问题,根据操作系统的知识,我们需要为互斥执行的语句创建临界区,并进行互斥访问。
饿汉式与懒汉式的区别在于,懒汉式是一种延迟加载的方式,刚开始赋值为null,直到加载的时候才创建对象;而饿汉式在一开始初始化的时候就创建了对象,分配了资源。
因为计算机进行I/O操作十分缓慢,因此延迟加载是一种提升性能的手段。有助于资源的合理使用。
单例模式的扩展与应用-缓存
- 既然我们可以控制全局生成一个对象,那么有没有需要生成一个以上的对象呢?
- 缓存设计与Singleton的扩展
集群。一台机器再强大,也不一定能抗住所有人的访问,所以可以用多台机器搭建一个集群。
//回避多线程的安全问题
#include
#include
如果我们对这个DEFAULT_KEY做一些事情,让它成为多例。
#include
#include
代码中写了10个instance,但是实际上只有5个instance被创建。
在实际应用中,可能集群需要维护5个单例,以便多用户访问和使用。