单例模式的介绍

单例模式的优点是只有一个对象,可以节省资源,提高运行速度,提供一个全局的访问点。
在使用过程中,写一个具有单例模式思想的程序可以很简单,但是如果要做到线程安全并且生成实例的过程中符合业务需求,是一件困难的事情。

Lazy mode(懒汉模式)

懒汉模式,会将实例化的时间延迟到正式调用接口的时候。
简单的实现方式

class singleton
{public:singleton* getInstance(){if(p_singletonIns == nullptr){p_singletonIns = new singleton();
}return p_singletonIns;
}private:singleton()=default;singleton(const singleton &cpSingleton) = delete;singleton& operator=(const singleton& cpSingleton) = delete;static singleton* p_singletonIns;
};singleton* singleton::p_singletonIns = nullptr;

上面的用例中,可以看到上面的p_singletonIns的在第一次调用getInstance()的时候会将p_singletonIns赋予一个实例的地址。这种延迟到使用时才进行实例化的做法,叫做懒汉模式。
但是这种方法不是线程安全的,同时会存在内存泄露的问题。
使用指针的方式的话,在创建实例的时候一般使用DCL(Double Check Lock), 双检测锁。代码如下所示

class singleton
{public:singleton* getInstance(){if(p_singletonIns == nullptr) // p1{std::lock_guard<std::mutex> lock();if(p_singletonIns == nullptr) // p2{p_singletonIns = new singleton(); // p3}}return p_singletonIns;}private:singleton()=default;singleton(const singleton &cpSingleton) = delete;singleton& operator=(const singleton& cpSingleton) = delete;static singleton* p_singletonIns;
};singleton* singleton::p_singletonIns = nullptr;

但是在使用过程中, p1的判断是存在一个风险,线程仍然不安全。就是在p3在new的时候,在new这个过程中,p_singletonIns的指针会被先赋值,然后开始创建内存。在并发的情况下,p1可能判断出p_singletonIns不是空指针,但是内存其实没有完全分配完成,那么造成返回p_singletonIns这个指针其实是不可用的。

使用原子变量的懒汉模式

在C++11的标准库中有原子变量的实现。使用原子变量就可以上述这种避免线程不安全的问题。

std::mutex mutexIns;
class singleton
{public:
static singleton* getInstance()
{if(p_singletonIns.load() == nullptr) // p1{std::lock_guard<std::mutex> lock(mutexIns);if(p_singletonIns.load() == nullptr) // p2{p_singletonIns.store(new singleton()); // p3}}return p_singletonIns.load();
}private:singleton()=default;singleton(const singleton &cpSingleton) = delete;singleton& operator=(const singleton& cpSingleton) = delete;static std::atomic<singleton*> p_singletonIns;
};
std::atomic<singleton*> singleton::p_singletonIns(nullptr);

使用局部静态变量的懒汉模式

使用局部静态变量也可以实现懒汉模式,使用局部静态变量在C++11之后是线程安全。这也是最为优雅的一种方式。

class singleton
{public:static singleton* getInstance(){singleton singletonIns;return &singletonIns;}private:singleton()=default;singleton(const singleton &cpSingleton) = delete;const singleton& operator=(const singleton& cpSingleton) = delete;
};

饿汉模式

饿汉模式:故名思意,一个饿坏的人会将一切能吃的东西都塞到肚子里,吃不下去的也要拽在手里。
在编程中这种模式的体现就在于资源在程序启动的时候就会分配好。而不是在运行时才进行资源分配。
使用饿汉模式编写单例模式相对简单一些。

class singleton
{public:singleton* getInstance(){return &singletonIns;}private:singleton()=default;singleton(const singleton &cpSingleton) = delete;singleton& operator=(const singleton& cpSingleton) = delete;static singleton singletonIns;
};
singleton singleton::singletonIns;

使用饿汉模式的话,singletonIns在C++中进行初始化的过程发生在程序加载的过程中,在main运行之前,也在调用getInstance()之前。这个初始化的过程也可以知道是确保线程安全的。同时也可以保证在程序结束之后自动析构。

关于资源泄露

首先资源泄露并不只是意味着内存泄露,还会指网络资源的释放,比如在分布式系统中,在程序退出时,让其他系统知道程序的退出等等场景。
在单例模式中,因为使用全局变量或者静态变量进行构造的时候,在程序退出时,会自动进行析构,通常是不存在资源泄漏的。在使用new的情况下,则不会自动进行析构,会存在资源泄漏的问题。下面介绍使用堆内存来构造单例模式的时候,如何在程序推出时,自动析构。

使用静态的嵌套对象来进行释放

使用嵌套的对象变量来释放,是因为单例模式的析构函数是private权限的,因此要使用嵌套对象来解决这个private的访问权限的问题。也满足高内聚编程原则。

std::mutex mutexIns;
class singleton
{public:
class deletor
{public:~deletor(){singleton *singletonIns;if((singletonIns = getInstance()) != nullptr){delete singletonIns;}}
};static singleton* getInstance()
{if(p_singletonIns.load() == nullptr) // p1{std::lock_guard<std::mutex> lock(mutexIns);if(p_singletonIns.load() == nullptr) // p2{p_singletonIns.store(new singleton()); // p3}}return p_singletonIns.load();
}private:singleton()=default;singleton(const singleton &cpSingleton) = delete;singleton& operator=(const singleton& cpSingleton) = delete;~singleton(){//do anything to make sure you have prevented resource leak.//...}static std::atomic<singleton*> p_singletonIns;static deletor   deletorIns;
};
std::atomic<singleton*> singleton::p_singletonIns(nullptr);
singleton::deletor   deletorIns;

线程安全的单例模式C++实现相关推荐

  1. Android之线程安全的单例模式,Adapter注意事项之引用传值

    线程安全的单例模式 单位模式一般写法如下: public static FestivalLab mInstance; private FestivalLab() { } public static F ...

  2. java 静态内部类 线程安全问题_单例模式的七种写法, 面试题:线程安全的单例模式...

    http://cantellow.iteye.com/blog/838473 http://meizhi.iteye.com/blog/537563 第一种(懒汉,线程不安全): Java代码  pu ...

  3. C++实现线程安全的单例模式

    C++实现线程安全的单例模式 1.单例模式 一个简单的单例模式很容易实现:构造函数声明为private或protect防止被外部函数实例化,内部保存一个private static的类指针保存唯一的实 ...

  4. 生产者消费者模型、信号量、线程池以及单例模式的实现

    生产者消费者模型!!---对典型的应用场景设计的解决方案 生产者与消费者模型应用场景:有线程不断的生产数据,有线程不断的处理数据. 数据的生产与数据的处理:放在同一个线程中完成,因为执行流只有一个,那 ...

  5. 静态内部类、静态变量的加载次数-理解静态内部类实现线程安全的单例模式

    百度众说纷纭的情况下就不如自己写例子测试理论,话不多说,上代码: public class Sta {public static long date=System.currentTimeMillis( ...

  6. 静态内部类、静态变量的加载次数-理解静态内部类实现线程安全的单例模式懒加载

    原贴:https://www.cnblogs.com/suncoolcat/p/3362230.html 写的很详细,需细细品味. 百度众说纷纭的情况下就不如自己写例子测试理论,话不多说,上代码: p ...

  7. JAVA的多线程、死锁、线程间通信、如何规避死锁、线程安全的单例模式

    主要内容: 多线程 线程和进程间的关系 Java中的线程理论 Java中线程类的实现方式 Java中线程的常用方法 线程安全性问题 线程间通信 线程的死锁 如何规避死锁 线程安全的单例模式 多线程 线 ...

  8. C#中线程安全的单例模式

    一.单例模式 ①单例模式的定义:是用来保证这个类在运行期间只会被创建一个实例,并提供一个访问它的全局访问点. ②单例模式的作用:保证一个类只有一个访问实例,节省系统资源. ③单例模式的特点:私有构造方 ...

  9. java线程池使用单例模式

    一.线程池不使用单例模式 import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;publ ...

  10. C++ static 变量和线程安全和单例模式

    static变量初始化顺序 1.1 全局变量.文件域的static变量和类的static成员变量在main函数执行之前初始化 1.2 局部静态变量在第一次被使用时初始化 static变量的线程安全 2 ...

最新文章

  1. 2047.句子中的有效单词数
  2. JSP与Servlet传值及对比
  3. 博途调试g120_【免费资料】西门子变频器调试软件汇总
  4. 新科高德发布2009.03版电子眼升级数据升级方法: 1. 新科2440方案机器内
  5. 深度学习,mxnet库的安装
  6. 【FPGA+PWM】基于FPGA的三相PWM整流器移相触发电路的设计与实现
  7. 插图详解Python解决汉诺塔问题
  8. SPSS到底怎么入门?这些干货你收藏了么?
  9. 告别windows,拥抱ubuntu
  10. 魔兽对战平台服务器更新维护什么,魔兽官方对战平台更新:公会系统正式上线!...
  11. 虚拟机VMware安装XP系统错误解决办法
  12. 公司是船,我在船上。
  13. 如何修改MySQL数据库密码
  14. (原创)Linux设备轮询机制分析
  15. 多线程有几种实现方法,同步有几种实现方法
  16. html页面转盘如何实现,html5制作转盘的详解及实例
  17. 原生js实现轮播图——小肉包
  18. jarsigner 错误: java.lang.RuntimeException: 密钥库加载: Invalid keystore format
  19. PointAugmenting: Cross-Modal Augmentation for 3D Object Detection论文笔记
  20. aspx 中轻松实现文件上传

热门文章

  1. PHP的威胁函数与PHP代码审计
  2. 电信wifi服务器不响应,电信老员工告诉你,为什么你家WiFi信号满格却上不了网?...
  3. 2013 Esri全球用户大会QA之元数据支持
  4. HanLP-地名识别调试方法
  5. 这个用JAVA开发的全开源商城系统可免费商用
  6. dex2jar android,dex2jar
  7. xp系统如可用计算机截图,WinXP系统电脑怎么截图 常见截图方法介绍
  8. 什么是 Java 内存模型( JMM )
  9. 吉林大学超星学习通02(1)
  10. FileUtils工具类