设计模式-单例模式

简介: 设计模式-单例模式

饿汉式单例模式:还没有获取实例对象,实例对象就已经产生了

class Singleton {
public:
  static Singleton* getInstance()
  {
    return &instance;
  }
private:
  static Singleton instance;
  Singleton()
  {
  }
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;
};
//静态成员变量类外初始化
Singleton Singleton::instance;
int main()
{
  Singleton *p1 = Singleton::getInstance();
  Singleton *p2 = Singleton::getInstance();
  Singleton *p3 = Singleton::getInstance();
  //如果没有私有化拷贝构造,这里会发生拷贝
  //Singleton p4 = *p1;
  cout << "p1: " << p1
    << " p2: " << p2
    << " p3: " << p3
    /*<< " p4: " << &p4*/ << endl;
  return 0;
}

饿汉式单例模式一定是线程安全的,因为静态成员变量在程序启动后就完成了初始化,不会有线程安全问题。但存在一些缺点,如果程序中始终没有用到该单例,并且在构造函数中又做了大量的事情,比如打开文件等等,这时无疑会影响效率。

懒汉式单例模式:唯一的实例对象,直到第一次获取它的时候,才产生

class Singleton {
public:
  static Singleton* getInstance()
  {
    if (instance == nullptr)
    {
      instance = new Singleton();
    }
    return instance;
  }
private:
  static Singleton *instance;
  Singleton()
  {
  }
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;
};
Singleton* Singleton::instance = nullptr;
int main()
{
  Singleton *p1 = Singleton::getInstance();
  Singleton *p2 = Singleton::getInstance();
  Singleton *p3 = Singleton::getInstance();
  cout << "p1: " << p1
    << " p2: " << p2
    << " p3: " << p3 << endl;
  return 0;
}

懒汉式解决了用到时再初始化的问题,但却不是线程安全的。

多线程环境下,构造对象时可能会出现问题:

static Singleton* getInstance()
  {
    if (instance == nullptr)
    {
      /*
      开辟内存
      构造对象
      给instance赋值
      */
      instance = new Singleton();
    }
    return instance;
  }

比如构造对象时会经历三步,第一个线程进来发现instance为空,进行开辟内存,但还没给instance赋值,这时instance还为空,这时第二个线程也可以进入构造,函数不可重入。同时,现代计算机为了加快运行速度,构造对象和给instance赋值的操作完全可能顺序相反,这时如果第二个线程发现instance不为空,直接返回,也会发生错误,因为这时完成了赋值却还没构造。

一种解决方法是加锁:

mutex mtx;
class Singleton {
public:
  static Singleton* getInstance()
  {
    lock_guard<std::mutex> guard(mtx);
    if (instance == nullptr)
    {
      /*
      开辟内存
      构造对象
      给instance赋值
      */
      instance = new Singleton();
    }
    return instance;
  }
  ...
}

但是这种情况对于单线程又不友好,每次都要加锁,锁的粒度太大。现在将锁放在if里面

mutex mtx;
class Singleton {
public:
  static Singleton* getInstance()
  {
    if (instance == nullptr)
    {
      lock_guard<std::mutex> guard(mtx);
      /*
      开辟内存
      构造对象
      给instance赋值
      */
      instance = new Singleton();
    }
    return instance;
  }
  ...
}

这时同样存在问题,第一个线程进入if,加锁,new对象,这时第二个线程判断instance为空,进入等待锁,第一个线程new完后,第二个线程拿到锁,同样会new对象。

所以这时就要进行双重检测:

static Singleton* getInstance()
  {
    if (instance == nullptr)
    {
      lock_guard<std::mutex> guard(mtx);
      if (instance == nullptr)
      {
        /*
        开辟内存
        构造对象
        给instance赋值
        */
        instance = new Singleton();
      }
    }
    return instance;
  }

这时便完成了线程安全的单例模式。

private:
  static Singleton *volatile instance;
  Singleton()
  {
  }
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;
};
Singleton*volatile Singleton::instance = nullptr;

一种更为简洁的写法是:

class Singleton {
public:
  static Singleton* getInstance()
  {
    //函数静态局部变量的初始化,在汇编指令上已经自动添加线程互斥指令了
    static Singleton instance;
    return &instance;
  }
private:
  Singleton()
  {
  }
  Singleton(const Singleton&) = delete;
  Singleton& operator=(const Singleton&) = delete;
};


目录
打赏
0
0
0
0
0
分享
相关文章
【设计模式】【创建型模式】单例模式(Singleton)
一、入门 什么是单例模式? 单例模式是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。它常用于需要全局唯一对象的场景,如配置管理、连接池等。 为什么要单例模式? 节省资源 场景:某些对象创
123 15
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
74 2
设计模式-单例模式练习
单例模式是Java设计模式中的重要概念,确保一个类只有一个实例并提供全局访问点。本文详解单例模式的核心思想、实现方式及线程安全问题,包括基础实现(双重检查锁)、懒汉式与饿汉式对比,以及枚举实现的优势。通过代码示例和类图,深入探讨不同场景下的单例应用,如线程安全、防止反射攻击和序列化破坏等,展示枚举实现的简洁与可靠性。
77 0
设计模式:单例模式
单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。它通过私有化构造函数、自行创建实例和静态方法(如`getInstance()`)实现。适用于数据库连接池、日志管理器等需要全局唯一对象的场景。常见的实现方式包括饿汉式、懒汉式、双重检查锁、静态内部类和枚举。线程安全问题可通过`synchronized`或双重检查锁解决,同时需防止反射和序列化破坏单例。优点是避免资源浪费,缺点是可能增加代码耦合度和测试难度。实际开发中应优先选择枚举或静态内部类,避免滥用单例,并结合依赖注入框架优化使用。
设计模式2:单例模式
单例模式是一种创建型模式,确保一个类只有一个实例,并提供全局访问点。分为懒汉式和饿汉式: - **懒汉式**:延迟加载,首次调用时创建实例,线程安全通过双重检查锁(double check locking)实现,使用`volatile`防止指令重排序。 - **饿汉式**:类加载时即创建实例,线程安全但可能浪费内存。 示例代码展示了如何使用Java实现这两种模式。
61 4
前端必须掌握的设计模式——单例模式
单例模式是一种简单的创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点。适用于窗口对象、登录弹窗等场景,优点包括易于维护、访问和低消耗,但也有安全隐患、可能形成巨石对象及扩展性差等缺点。文中展示了JavaScript和TypeScript的实现方法。
169 13
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
87 2
Java编程中的设计模式:单例模式的深度剖析
【10月更文挑战第41天】本文深入探讨了Java中广泛使用的单例设计模式,旨在通过简明扼要的语言和实际示例,帮助读者理解其核心原理和应用。文章将介绍单例模式的重要性、实现方式以及在实际应用中如何优雅地处理多线程问题。
112 4
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
91 1
登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问