单例模式(Singleton Pattern)是设计模式中最简单的,主要是确保该类只有一个实例。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

1、特点

  • 保证一个类仅有一个实例,并提供一个访问它的全局访问点。
  • 避免一个全局使用的类频繁地创建与销毁。

    2、代码实现

    构造单例模式的步骤:

    1. 私有化构造函数,防止被外部函数直接实例化。
    2. 声明一个private static 的类指针,保存唯一的实例。
    3. 提供一个全局的static方法(全局访问点)。
    4. 该方法也返回单例类唯一的实例

      懒汉式:

  • 在类加载时,不创建实例,因此类加载速度快,但运行时获取对象的速度慢

是线程不安全的,考虑两个线程同时首次调用getInstance方法且同时检测到p是NULL值,则两个线程会同时构造一个实例给p,这是严重的错误!同时,这也不是单例的唯一实现!

  1. // 懒汉式,线程不安全
  2. class Singleton
  3. {
  4. private:
  5. Singleton(){};
  6. static Singleton* instance;
  7. public:
  8. static Singleton* getInstance() {
  9. if (instance == nullptr) {
  10. instance = new Singleton;
  11. }
  12. return instance;
  13. }
  14. }
  15. Singleton* Singleton::instance = 0;
  16. //懒汉式,加锁解决线程安全问题。
  17. class Singleton
  18. {
  19. private:
  20. Singleton(){
  21. pthread_mutex_init(&mutex,NULL);
  22. };
  23. static Singleton* instance;
  24. public:
  25. static pthread_mutex_t mutex;
  26. static Singleton* getInstance() {
  27. pthread_mutex_lock(&mutex);
  28. if (instance == nullptr)
  29. instance = new Singleton;
  30. pthread_mutex_unlock(&mutex);
  31. return instance;
  32. }
  33. }
  34. pthread_mutex_t Singleton::mutex;
  35. Singleton* Singleton::instance = 0;
  36. //懒汉式,可通过静态内部局部变量的方法解决线程安全问题。
  37. /*在getInstance函数里定义一个静态的实例,也可以保证拥有唯一实例,
  38. *在返回时只需要返回其指针就可以。但是内存分配是在静态存储区,需要考量。
  39. */
  40. class Singleton
  41. {
  42. private:
  43. Singleton(){};
  44. public:
  45. // 使用指针而不是引用是为了避免拷贝构造函数进行拷贝
  46. static Singleton* getInstance() {
  47. static Singleton instance;
  48. return &instance;
  49. }
  50. }
  51. int main()
  52. {
  53. Singleton* p = Singleton::getInstance();
  54. return 0;
  55. }

饿汉式:

  • 在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快

线程安全,类的静态成员变量,归该类所有成员,而非某个对象。

  1. //饿汉式,线程安全。
  2. class Singleton
  3. {
  4. private:
  5. Singleton(){};
  6. static Singleton* instance;
  7. public:
  8. static Singleton* getInstance() {
  9. return instance;
  10. }
  11. }
  12. Singleton* Singleton::instance = new Singleton;
  13. int main()
  14. {
  15. Singleton* p = Singleton::getInstance();
  16. return 0;
  17. }

单例模板类 - 奇异递归模板(CRTP,The Curiously Recurring Template Pattern)模式

  1. template <typename TYPE>
  2. class Singleton {
  3. public
  4. static TYPE* getInstance() {
  5. Mutex::Autolock _l(mLock);
  6. if (instance == 0)
  7. instance = new TYPE();
  8. return instance;
  9. }
  10. //构造函数需要是 protected,这样子类才能继承;
  11. protected:
  12. Singleton(){};
  13. ~Singleton(){};
  14. private:
  15. static Mutex mLock;
  16. static TYPE* instance;
  17. }
  18. template <typename TYPE> Mutex Singleton<TYPE>::mLock;
  19. template <typename TYPE> TYPE* Singleton<TYPE>::instance = 0;
  20. class ABCSingleton : public Singleton<ABCSingleton>
  21. {
  22. private:
  23. //声明为友元,以便访问私有的构造和析构。
  24. friend class Singleton<ABCSingleton>;
  25. }

3、应用场景

  1. 由于要进行线程同步,所以在访问量比较大,或者可能访问的线程比较多时,采用饿汉实现,可以实现更好的性能。这是以空间换时间。
  2. 在访问量较小时,采用懒汉实现。这是以时间换空间。
  3. factory 模式下,因为要包含很多实例,用饿汉模式。需要更多的空间,可考虑用懒汉模式。因为工厂模式缓存了很多实例、得考虑效率问题,因为这个类一加载则把所有实例一一创建

    4、参考链接

    面试中的Singleton: https://www.cnblogs.com/loveis715/archive/2012/07/18/2598409.html