设计模式-单例模式

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

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

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;
};


相关文章
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
27 2
|
13天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
|
22天前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入理解与应用
【10月更文挑战第22天】 在软件开发中,设计模式是解决特定问题的通用解决方案。本文将通过通俗易懂的语言和实例,深入探讨PHP中单例模式的概念、实现方法及其在实际开发中的应用,帮助读者更好地理解和运用这一重要的设计模式。
15 1
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发中,设计模式是提高代码可维护性、扩展性和复用性的关键技术之一。本文将通过探讨单例模式,一种最常用的设计模式,来揭示其在PHP中的应用及优势。单例模式确保一个类仅有一个实例,并提供一个全局访问点。通过实际案例,我们将展示如何在PHP项目中有效实现单例模式,以及如何利用这一模式优化资源配置和管理。无论是PHP初学者还是经验丰富的开发者,都能从本文中获得有价值的见解和技巧,进而提升自己的编程实践。
|
1月前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy&lt;T&gt;` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
29 1
|
1月前
|
设计模式 缓存 数据库连接
探索PHP中的设计模式:单例模式的实现与应用
在PHP开发中,设计模式是提高代码可复用性、可维护性和扩展性的重要工具。本文将深入探讨单例模式(Singleton Pattern)的基本概念、在PHP中的实现方式以及实际应用场景。单例模式确保一个类仅有一个实例,并提供全局访问点。通过具体代码示例和详细解释,我们将展示如何在PHP项目中有效利用单例模式来解决实际问题,提升开发效率和应用性能。
|
1月前
|
设计模式 存储 测试技术
PHP中的设计模式:单例模式的深入解析与实践
在PHP开发领域,设计模式是解决常见问题的最佳实践。本文将深入探讨单例模式,一种确保类只有一个实例的设计模式,并提供实际应用示例。我们将从单例模式的基本概念讲起,通过实际案例展示如何在PHP中实现单例模式,以及它在不同场景下的应用和优势。最后,我们会探讨单例模式的优缺点,帮助开发者在实际项目中做出明智的选择。
|
1月前
|
设计模式 SQL 安全
PHP中的设计模式:单例模式的深入探索与实践在PHP开发领域,设计模式是解决常见问题的高效方案集合。它们不是具体的代码,而是一种编码和设计经验的总结。单例模式作为设计模式中的一种,确保了一个类仅有一个实例,并提供一个全局访问点。本文将深入探讨单例模式的基本概念、实现方式及其在PHP中的应用。
单例模式在PHP中的应用广泛,尤其在处理数据库连接、日志记录等场景时,能显著提高资源利用率和执行效率。本文从单例模式的定义出发,详细解释了其在PHP中的不同实现方法,并探讨了使用单例模式的优势与注意事项。通过对示例代码的分析,读者将能够理解如何在PHP项目中有效应用单例模式。
|
1月前
|
设计模式 存储 数据库连接
PHP中的设计模式:单例模式的深入探讨与实践
在PHP开发领域,设计模式是提升代码可读性、可维护性和扩展性的重要工具。本文聚焦于单例模式——一种确保类只有一个实例,并提供全局访问点的设计模式。我们将从定义、实现方式、应用场景以及在PHP框架中的运用等方面进行详细探讨,旨在帮助PHP开发者更好地理解和运用单例模式。
|
27天前
|
设计模式 安全 Java
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
Kotlin教程笔记(57) - 改良设计模式 - 单例模式
25 0