单例模式(Singleton Pattern)是设计模式中最简单的,主要是确保该类只有一个实例。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1、特点
是线程不安全的,考虑两个线程同时首次调用getInstance方法且同时检测到p是NULL值,则两个线程会同时构造一个实例给p,这是严重的错误!同时,这也不是单例的唯一实现!
// 懒汉式,线程不安全class Singleton{private:Singleton(){};static Singleton* instance;public:static Singleton* getInstance() {if (instance == nullptr) {instance = new Singleton;}return instance;}}Singleton* Singleton::instance = 0;//懒汉式,加锁解决线程安全问题。class Singleton{private:Singleton(){pthread_mutex_init(&mutex,NULL);};static Singleton* instance;public:static pthread_mutex_t mutex;static Singleton* getInstance() {pthread_mutex_lock(&mutex);if (instance == nullptr)instance = new Singleton;pthread_mutex_unlock(&mutex);return instance;}}pthread_mutex_t Singleton::mutex;Singleton* Singleton::instance = 0;//懒汉式,可通过静态内部局部变量的方法解决线程安全问题。/*在getInstance函数里定义一个静态的实例,也可以保证拥有唯一实例,*在返回时只需要返回其指针就可以。但是内存分配是在静态存储区,需要考量。*/class Singleton{private:Singleton(){};public:// 使用指针而不是引用是为了避免拷贝构造函数进行拷贝static Singleton* getInstance() {static Singleton instance;return &instance;}}int main(){Singleton* p = Singleton::getInstance();return 0;}
饿汉式:
- 在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快
线程安全,类的静态成员变量,归该类所有成员,而非某个对象。
//饿汉式,线程安全。class Singleton{private:Singleton(){};static Singleton* instance;public:static Singleton* getInstance() {return instance;}}Singleton* Singleton::instance = new Singleton;int main(){Singleton* p = Singleton::getInstance();return 0;}
单例模板类 - 奇异递归模板(CRTP,The Curiously Recurring Template Pattern)模式
template <typename TYPE>class Singleton {public:static TYPE* getInstance() {Mutex::Autolock _l(mLock);if (instance == 0)instance = new TYPE();return instance;}//构造函数需要是 protected,这样子类才能继承;protected:Singleton(){};~Singleton(){};private:static Mutex mLock;static TYPE* instance;}template <typename TYPE> Mutex Singleton<TYPE>::mLock;template <typename TYPE> TYPE* Singleton<TYPE>::instance = 0;class ABCSingleton : public Singleton<ABCSingleton>{private://声明为友元,以便访问私有的构造和析构。friend class Singleton<ABCSingleton>;}
3、应用场景
- 由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
- 在访问量较小时,采用懒汉实现。这是以时间换空间。
- factory 模式下,因为要包含很多实例,用饿汉模式。需要更多的空间,可考虑用懒汉模式。因为工厂模式缓存了很多实例、得考虑效率问题,因为这个类一加载则把所有实例一一创建
4、参考链接
面试中的Singleton: https://www.cnblogs.com/loveis715/archive/2012/07/18/2598409.html
