一、懒汉模式
即第一次调用该类实例的时候才产生一个新的该类实例,并在以后仅返回此实例。
需要用锁,来保证其线程安全性:原因:多个线程可能进入判断是否已经存在实例的if语句,从而non thread safety。
使用double-check来保证thread safety。但是如果处理大量数据时,该锁才成为严重的性能瓶颈。
1、静态成员实例的懒汉模式
C++代码:
class Singleton{ static Singleton * instance; static std::mutex m; Singleton(){} public: static Singleton* getInstance(); }; Singleton* Singleton::getInstance(){ if(instance == nullptr){ std::lock_guard<std::mutex> lg(m);//这里使用了std::lock_guard来达到RAII if(instance == nullptr){ instance = new Singleton(); } } return instance; } Singleton * Singleton::instance = nullptr; std::mutex Singleton::m; //静态mutex这样初始化我还是第一次写。。
这一模式算是最经典的了,在普通单例模式中添加了线程安全锁。
2、内部静态实例的懒汉模式
class Singleton { private: Singleton(){} public: static Singleton* getInstance(){ //Lock(); //not needed after C++11 static Singleton instance; //UnLock(); //not needed after C++11 return &instance; //注意返回的是地址 } };
使用内部静态实例我还是第一次看到,感觉挺巧妙的,而且C++11之后内部静态变量初始化编译器保证做到线程安全,比较方便的写法。
二、饿汉模式
即无论是否调用该类的实例,在程序开始时就会产生一个该类的实例,并在以后仅返回此实例。
由静态初始化实例保证其线程安全性,WHY?因为静态实例初始化在程序开始时进入主函数之前就由主线程以单线程方式完成了初始化,不必担心多线程问题。
故在性能需求较高时,应使用这种模式,避免频繁的锁争夺。
class Singleton { private: static Singleton* instance; Singleton(){} public: static Singleton* getInstance() { return instance; } }; Singleton* Singleton::instance = new Singleton();
感觉这种实现方法挺好的,锁都不用加。
参考:https://peach.oschina.io/post/c++_%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8%E7%9A%84%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/
https://zh.cppreference.com/w/cpp/thread/lock_guard