设计模式:
设计模式是一套被反复使用,多数人知晓的,经过分类的,代码设计经验的总结。
目的:为了代码可重用性,让代码更容易被他理解,保证代码可靠性。
单列模式:一个类只能创建一个对象,即单列模式,该模式可以保证系统中该类只有一个实例,并提供一个访问他的全局访问点,该实例被所有程序模块共享。
比如:在某个服务器程序中,该服务器的配置信息存放在一个文件夹中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象在通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理
单例模式有两种实现模式:饿汉模式;懒汉模式
饿汉模式:就是说不管你将来用不用,程序启动时就创建一唯一的实例对象
优点:简单
缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定
1 //饿汉模式 2 class Singleton { 3 public: 4 static Singleton* GetInstance() { 5 return &m_instance; 6 } 7 private: 8 // 构造函数私有 9 Singleton(){}; 10 11 // C++98 防拷贝 12 Singleton(Singleton const&); 13 Singleton& operator=(Singleton const&); 14 15 // or 16 17 // C++11 18 Singleton(Singleton const&) = delete; 19 Singleton& operator=(Singleton const&) = delete; 20 static Singleton m_instance; 21 }; 22 Singleton Singleton::m_instance; // 在程序入口之前就完成单例对象的初始化
如果这个单例对象再多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。
懒汉模式:如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊,初始化网络连接啊,读取文件啊等等。而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。所以这中情况是哟个懒汉模式(延迟加载)更好。
优点:第一次使用实例对象时,创建对象,进程启动无负载,多个单例实例启动顺序自由的控制。
缺点:复杂
1 //懒汉模式 2 #include <iostream> 3 #include <mutex> 4 #include <thread> 5 using namespace std; 6 7 class Singleton { 8 public: 9 static Singleton* GetInstance() { 10 // 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全 11 if (nullptr == m_pInstance) { 12 m_mtx.lock(); 13 if (nullptr == m_pInstance) { 14 m_pInstance = new Singleton(); 15 } 16 m_mtx.unlock(); 17 } 18 return m_pInstance; 19 } 20 21 // 实现一个内嵌垃圾回收类 22 class CGarbo { 23 public: 24 ~CGarbo(){ 25 if (Singleton::m_pInstance) 26 delete Singleton::m_pInstance; 27 } 28 }; 29 30 /*定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象*/ 31 static CGarbo Garbo; 32 33 private: 34 // 构造函数私有 35 Singleton(){}; 36 37 // 防拷贝 38 Singleton(Singleton const&); 39 Singleton& operator=(Singleton const&); 40 41 static Singleton* m_pInstance; // 单例对象指针 42 static mutex m_mtx; //互斥锁 43 }; 44 45 Singleton* Singleton::m_pInstance = nullptr; 46 Singleton::CGarbo Garbo; 47 mutex Singleton::m_mtx; 48 49 void func(int n) { 50 cout<< Singleton::GetInstance() << endl; 51 } 52 53 // 多线程环境下演示上面GetInstance()加锁和不加锁的区别。 54 int main() { 55 thread t1(func, 10); 56 thread t2(func, 10); 57 58 t1.join(); t2.join(); 59 60 cout << Singleton::GetInstance() << endl; 61 cout << Singleton::GetInstance() << endl; 62 }