多线程下的单例模式实现

  • 一,单线程下的单实例
    • 1, 懒汉模式
    • 2, 饿汉模式
  • 二,多线程下的单实例
    • 1,加锁
    • 2,原子操作

单实例设计模式是我们平常接触最多的一种设计模式,它的特点在于保证一个类只有一个实例,并且对类成员的访问都是通过一个全局访问点来进行的。单实例主要用在整个场景中只能有一个该操作类对象,不允许再有其他的该操作类对象,比如:Http传输管理类,线程池管理类等。下面我们对单线程和多线程不同模式下的单实例实现分别进行分析。

一,单线程下的单实例

单例模式的结构图如下:

     为了避免在外部创建类对象,我们需要将单例类的构造函数设置为私有,并且提供一个静态的接口来创建唯一实例对象。单例模式根据创建实例的时机又可以分为饿汉模式和懒汉模式。

1, 懒汉模式

懒汉模式即当需要的时候才会去new对象,代码实现如下:

class Singelton
{
private:Singelton() {}static Singelton* s_singleton;public:static Singelton* GetInstance(){if (s_singleton == NULL){s_singleton = new Singelton();}return s_singleton;}
};
Singelton* Singelton::s_singleton = NULL;//注意静态变量类外初始化

当多个线程同时调用GetInstance()时,由于内部的new操作并没有加锁,会出现以下两种情况:
A, 多个线程同时对一个变量进行写操作,地址访问冲突,导致程序崩溃;
B, 有一个临界点,同时new了两个对象,违背了单实例的原则,返回的类指针不唯一相同。
     因此,懒汉模式在是多线程不安全的。

2, 饿汉模式

饿汉模式即在调用接口获取对象之前直接先new一个对象,代码实现如下:

class Singelton
{
private:Singelton() {}static Singelton* s_singleton;public:static Singelton* GetInstance(){return s_singleton;}
};
Singelton* Singelton::s_singleton = new Singelton;//注意静态变量类外初始化

由于饿汉模式类对象的创建是在一个静态变量初始化时new出来的,那么在多线程中调用GetInstance()并不会有问题(全局变量和静态变量是在main函数之前初始化的)

二,多线程下的单实例

针对上述两种单实例模式的实现,可以知道:饿汉模式是线程安全的,懒汉模式是线程不安全的。下面我们来实现线程安全的懒汉模式。

1,加锁

通过锁来实现,在每次new之前加锁,new完成后释放锁,保证永远只有一个线程对该静态类指针进行赋值操作,代码如下:

#include <mutex>class Singelton
{
private:Singelton() {}static Singelton* s_singleton;static std::mutex s_cvMutex; // 互斥锁.public:static Singelton* GetInstance(){if (s_singleton == nullptr){std::lock_guard<std::mutex> lck(s_cvMutex);if (s_singleton == nullptr){s_singleton = new Singelton;}
}return s_singleton;}
};
Singelton* Singelton::s_singleton = nullptr;//注意静态变量类外初始化
std::mutex Singelton::s_cvMutex;

这里有一点需要注意,在加锁之后,new之前,又加了一重判空操作,这一步是为了保证多个线程同时进入了第一层判空语句中,当一个线程new完之后,如果不加第二重判空,那么第二个线程会再次进行new操作,导致实例不唯一。

2,原子操作

单纯的原子操作并没有锁的功能,需要配合上:if + while + Sleep(当然,也可以说是if + while,不去Sleep也可以),具体代码实现如下:

class Singelton
{
private:Singelton() {}public:static Singelton* GetInstance(){if (g_singleton == NULL){long pre_value = ::InterlockedExchange(&g_nLock, 1); //返回原来的值if (pre_value != 0){while (g_singleton == NULL){::Sleep(50);}}if (g_singleton == NULL){g_singleton = new Singelton;}}return g_singleton;}};
Singelton* volatile g_singleton = nullptr;
long volatile g_nLock = 0;

多个线程同时调用InterlockedExchange,只能有一个线程得到0,保证只初始化一次,其余线程进入while循环等待,直到g_singleton非空。
     大家可以注意到,这里还用到了volatile关键字,volatile一般有两个好处:1是使得多个线程直接操作内存,变量被某个线程改变后其它线程也可以及时看到改变后的值;2是阻止编译器优化操作volatile变量的指令执行顺序。这里如果不使用它,就可能导致编译器调整汇编指令的顺序,分配完内存就直接把地址赋值给g_singleton指针,后面再调用构造函数,它这样调整的理由可能是这样子:分配到的内存指针在后续的执行中没有被修改,先赋值给g_singleton和晚赋值给g_singleton没有区别,这就导致了半成品对象的产生。

多线程下的单例模式实现相关推荐

  1. 多线程下的单例模式详解

    1. 单例模式 (1) 单例模式简介 (2) 实现方式 ① 饿汉式 ② 懒汉式 2. 多线程下的单例模式 (1) Synchronized (2) 双重检查锁 (3) 双重检查锁+Volatile 补 ...

  2. 设计模式---单例模式(多线程下的单例模式)

    1>单例类 package com.test.sigleton;public class SingletonTest {public static int num=0;//用于记录该类被实例化的 ...

  3. Python多线程下实现单例模式,以及limit实例模式

    多线程环境下实现单例模式 下面介绍了两种Python实现单例模式的方法 1.重写__new__方法实现多线程情况下的单例模式 用new方法实现单例模式 import time, threadingcl ...

  4. C++ 多线程下的单例模式

    /*代码中经常会使用到单例模式,单例模式就是隐藏构造函数,提供获取一个实例的静态方法.但是在多线程场景下,单例模式会有一些不同.例如Config类的instance方法如下*///获取一个实例(对外接 ...

  5. 多线程下的单例模式你真的了解吗?

    第一种(懒汉,线程不安全): public class Singleton { private static Singleton instance; private Singleton (){} pu ...

  6. 多线程抢票_java多线程下模拟抢票

    我们设置三个对象分别同时抢20张票,利用多线程实现. public class Web123506 implements Runnable{ private int ticteksNums=20;// ...

  7. [Java]Java的静态构造函数 多线程下安全的单例模式

    我也在看书的时候 看到C#的静态构造方法 也在想JAVA有没有同样的东西. 先来看一看为什么C#的静态构造方法为什么会存在 我们平常普通的做法是 public class Teacher {priva ...

  8. java 多线程的单例模式,Java多线程中的单例模式两种实现方式

    Java多线程中的单例模式 一.在多线程环境下创建单例 方式一: package com.ietree.multithread.sync; public class Singletion { priv ...

  9. Java多线程案例之单例模式(懒汉,饿汉,枚举)

    ⭐️前面的话⭐️ 本篇文章将介绍Java多线程中的几个典型案例之单例模式,所谓单例模式,就是一个类只有一个实例对象,本文将着重介绍在多线程的背景下,单例模式的简单实现.

最新文章

  1. JavaScript里面三个等号和两个等号的区别
  2. 2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 F Color it
  3. IIS FTP部分文件上传报错451的原因及解决方法
  4. python消息推送_Python阿里云消息推送调用API
  5. 把Springboot项目部署到服务器上和结束运行
  6. react-hooks_在5分钟内学习React Hooks-初学者教程
  7. 不再单打独斗?中国移动联合多企业组建医疗数据公司
  8. 207. 课程表/210. 课程表 II
  9. cortex-m 2017 whitepaper (English and Chinese)
  10. SQL2005开发版下载地址
  11. 王牌英雄怎么服务器维护了,王牌英雄steam版无法运行问题解决方法_3DM单机
  12. 支持团队开发的UML建模和CASE工具MagicDraw
  13. 机器学习基础概念(三):归纳与演绎
  14. Windows Server2008 Server 安装Telnet服务
  15. 如何用友远程到服务器,怎么安装用友T3远程通
  16. 本机号码校验不只是免输密码、免输短信验证码
  17. cast 和convert和concat详解以及mysql和sqlserver兼容问题
  18. 九宫格动态密码--快速入门
  19. 别人家的公司年终奖52个月工资-互联网企业年终裁员脸在哪
  20. Cocos2d-x 2.0 百例精讲:如何让一个精灵跟随触点移动

热门文章

  1. 市值1000亿的“占卜”生意:20玩家相继获投,最高融资3000万
  2. html字号不能单数吗,HTML 字体大小为什么一般都是偶数
  3. TI charger ic手册分析
  4. SFKP • 计算机百科丨云计算发展风云
  5. 使用Windows Live照片库创建全景照片
  6. 自定义标签 TagSupport
  7. 电脑突然无法复制粘贴Ctrl+C和Ctrl+V怎么回事?
  8. html国字型布局,结合CSS3的布局新特征谈谈常见布局方法
  9. 背景噪声库_背景或环境噪声的最佳场所
  10. 华为徐兴海、区波:面向业务创新的大数据平台及商业实践