单例模式
保证类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享
单例模式的要点有三个:
- 单例类只能有一个实例
- 必须自行创建这个实例
- 必须自行向整个系统提供这个实例
注意点
- 实例控制: 单例模式会阻止其他对象实例化自己的单例对象的副本,从而确保所有对象都访问唯一实例
- 灵活性: 因为类控制实例化过程,所以类可以灵活更改实例化过程
- 开销: 虽然数量很少,但如果每次对象请求引用时都要检查是否存在类的实例,将仍然需要一些开销,这个问题可以通过静态初始化解决此问题。定义一个私有的静态指针instance,和一个公有的静态函数 GetInstance()。
优点:
- 在内存中只有一个对象,节省内存空间
- 避免频繁的创建销毁对象,可以提高性能
- 避免对共享资源的多重占用
- 可以全局访问
适用场景:
- 需要频繁实例化然后销毁的对象
- 创建对象耗时过多或者耗资源过多,但又经常用到的对象
- 有状态的工具类对象
- 频繁访问数据库或文件的对象
- 以及其他要求只有一个对象的场景
懒汉
故名思义,不到万不得已就不会去实例化类,也就是说在第一次用到类实例的时候才会去实例化
在访问量较小时,采用懒汉实现。这是以时间换空间。
经典懒汉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class Singleton{ public: static Singleton* GetInstance(); private: Singleton(){}; Singleton(const Singleton&){}; Singleton& operator = (const Singleton&){}; static Singleton* instance; };
Singleton* Singleton::instance = NULL; Singleton* Singleton::GetInstance(){ if(instance == NULL){ instance = new Singleton(); } return instance; }
|
懒汉模式下,在定义instance变量时先等于NULL,在调用GetInstance()方法时,再判断是否要赋值。这种模式,并非是线程安全的,因为多个线程同时调用GetInstance()方法,就可能导致有产生多个实例。要实现线程安全,就必须加锁。
加锁懒汉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| class Singleton { private: Singleton(){ pthread_mutex_init(&mutex); }; Singleton(const Singleton&){}; Singleton& operator=(const Singleton&){}; static Singleton* instance; public: static pthread_mutex_t mutex; static Singleton* GetInstance(); };
pthread_mutex_t Singleton::mutex; Singleton* Singleton::instance = NULL;
Singleton* Singleton::GetInstance(){ if(instance == NULL){ pthread_mutex_lock(&mutex); if(instance == NULL) instance = new Singleton(); pthread_mutex_unlock(&mutex); } return instance; }
|
饿汉
线程安全:还未使用变量时,已经对instance进行赋值,就像很饥饿的感觉。在多线程环境下肯定是线程安全的,因为不存在多线程实例化的问题。
饿了肯定要饥不择食,所以在单例类定义的时候就进行实例化。
由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Singleton{ public: static Singleton* GetInstance(); private: Singleton(const Singleton&){}; Singleton& operator=(const Singleton&){}; Singleton(){}; static Singleton* instance; };
Singleton* Singleton::instance = new Singleton(); Singleton* Singleton::GetInstance(){ return instance; }
|