C++:单例模式——线程安全模式、饥汉模式、懒汉模式
简介
单例模式:意思是一个类只能实例化一个对象,且无法通过拷贝构造,赋值构造等方法构造对象。
在理解单例模式之前,要先了解 static关键字的用法可在此查看:
链接: static关键字详解.
目录
- 简介
- 线程安全模式
- 饥汉模式
- 懒汉模式
- 总结
线程安全模式
class Object
{private:int value;static Object instance;
private:Object(int x = 0) : value(x) {}Object(const Object& obj) = delete;Object& operator =(const Object& obj) = delete;public:static Object& GetInstance(){return instance;}
};Object Object::instance(10);
可以看出无法通过构造函数实例化对象,只有一个静态的对象。
调用示例:
#include<thread>void funa()
{Object& obja = Object::GetInstance();cout << "obja " << &obja << endl;
}
void funb()
{Object& objb = Object::GetInstance();cout << "objb " << &objb << endl;
}
int main(void)
{thread thra(funa);thread thrb(funb);thra.join();thrb.join();return 0;
}
在引入多线程时,所使用的仍然是同一个对象。
饥汉模式
class Object
{private:int value;
private:Object(int x = 0) : value(x) {}Object(const Object& obj) = delete;Object& operator =(const Object& obj) = delete;public:static Object& GetInstance(int x){static Object instance(x);return instance;}
};
如果我以多线程示例来使用这个类:
#include<thread>void funa()
{Object& obja = Object::GetInstance(10);cout << "obja " << &obja << endl;
}
void funb()
{Object& objb = Object::GetInstance(20);cout << "objb " << &objb << endl;
}int main(void)
{thread thra(funa);thread thrb(funb);thra.join();thrb.join();return 0;
}
在构造该对象时,仍然会有标记位的产生,多线程会导致两个线程竞争初始化的资源,会导致这个对象初始化不明确。
标记位如何理解?
可以看static关键字详解.
懒汉模式
如果不希望在程序运行时就构造这个单例对象,而是在我们需要的时候才构造出来,就可使用 懒汉模式。
class Object
{private:int value;static Object* pobj;
private:Object(int x = 0) : value(x) {}Object(const Object& obj) = delete;Object& operator =(const Object& obj) = delete;public:static Object* GetInstance(int x){if (pobj == nullptr){pobj = new Object(10);}return pobj;}
};
Object* Object::pobj = nullptr;
但是这种模式相比刚才,不仅线程不安全,还会造成更严重的后果。
多线程示例:
#include<thread>void funa()
{Object* obja = Object::GetInstance(10);cout << "obja " << &obja << endl;
}
void funb()
{Object* objb = Object::GetInstance(20);cout << "objb " << &objb << endl;
}int main(void)
{thread thra(funa);thread thrb(funb);thra.join();thrb.join();return 0;
}
在第一次运行时,可以发现两个指针所指向的对象的地址是同一个,好像并没有造成影响。。。
但如果在类的 GetInstance()函数中让线程睡眠一会儿,会怎么样?
static Object* GetInstance(int x)
{if (pobj == nullptr){// 睡眠std::this_thread::sleep_for(std::chrono::milliseconds(10));pobj = new Object(10);}return pobj;
}
运行结果:
产生了两个对象,这会导致严重后果。
解决方法: 加锁
#include<mutex>
std::mutex mtx;static Object* GetInstance(int x)
{std::lock_guard<std::mutex> lock(mtx);if (pobj == nullptr){std::this_thread::sleep_for(std::chrono::milliseconds(10));pobj = new Object(10);}return pobj;
}
运行示例:
可以看出,不管程序运行多少次,两个指针都指向同一个对象。
总结
- 线程安全模式是因为 对象直接在数据区构造,不管如何使用,其位置都是固定的;
- 饥汉模式也是在数据区构造对象,位置固定,其中的麻烦是在多线程下构造时,会导致存储的值不明确。 比懒汉模式强的一点是不会在堆区构造。
- 而懒汉模式使用 new来构造的对象,分布在堆区不同位置,所以不安全,需要加锁。
C++:单例模式——线程安全模式、饥汉模式、懒汉模式相关推荐
- 单例模式——饿汉模式懒汉模式
目录 一.什么是单例模式? 二.单例模式的应用场景 三.两种典型的方式实现单例模式 1.饿汉模式 2.懒汉模式 3.理解懒汉模式和饿汉模式 四.单例模式和线程的关系 1.饿汉模式是否线程安全? 2.懒 ...
- 单例模式之饿汉模式懒汉模式
前言 单例模式能保证某个类在程序中只存在唯一一份实例,而不会创建出多个实例,比如 JDBC 中的 DataSource 实例就只需要一个.单例模式具体的实现方式有"饿汉" 和 &q ...
- 单例模式之饿汉、懒汉模式
目录 1.单例模式 1.1 饿汉模式 1.2 懒汉模式 1.单例模式 单例模式能保证类在程序中只存在唯一一份实例.这一点在很多场景中都需要,比如JDBC中的DataSource实例就只需要一个. 单例 ...
- DBCP使用BasicdataSource连接(两种单例模式-----饿汉和懒汉模式)
DBCP使用BasicDataSource连接 BasicDataSource实现DataSource的接口,可以进行简单的数据库连接 第一种:懒汉模式:顾名思义,"懒",只有在调 ...
- 单例模式的创建(饿汉模式懒汉模式)
- 单例模式的四种实现方式(饿汉模式、懒汉模式、静态内部类、枚举类)
首先,设计模式是我们程序员在软件开发过程中面临的一般问题的解决方案,通过学习设计模式可以使我们在编程时更加有条理性,同时培养我们写代码的思维能力,从而提高我们的工作效率.接下来就跟着博主的脚步往下走吧 ...
- C++单例模式 : 懒汉模式 与 饿汉模式
单例模式: 只能有一个实例,有懒汉和饿汉区分,实现核心思想: 1.构造函数私有化 2.使用静态函数作为接口来获取类对象 1.懒汉模式: ...
- 2023-01-26 JS设计模式-单例模式:单例模式的原理和实现,懒汉模式和饿汉模式,单例模式实现登录框
文章目录 1.什么是单例模式? 介绍 特点 结构 2.如何实现一个单例模式? 思路 实现代码 3.单例模式的优缺点 4.懒汉模式和饿汉模式 懒汉模式:一开始不会实例化,什么时候用才new出来实例化 饿 ...
- java设计模式之单例模式|单例模式之饿汉模式、懒汉模式、枚举方式|最详细的6种懒汉模式详解
目录 一.单例模式 二.饿汉模式和懒汉模式 1.饿汉模式,线程安全 2.懒汉模式 懒汉模式1,线程不安全(不常用) 懒汉模式2,线程安全(不常用) 懒汉模式3,线程安全,双重校验(不常用) 懒汉模式4 ...
- 单例模式的原理/懒汉模式/饿汉模式以及不同版本的单例模式程序
单例模式 单例模式定义 懒汉模式与饿汉模式 懒汉模式 饿汉模式 懒汉模式和饿汉模式的区别 懒汉模式的不同版本 版本一 版本二 版本三 版本四 单例模式定义 保证一个类仅有一个实例,并提供一个该实例的全 ...
最新文章
- [Jobdu] 题目1504:把数组排成最小的数
- 【面试虐菜】—— JAVA面试题(2)
- 用python处理excel数据的优势-python数据分析相对于bi和excel的优势是什么?
- SpringBoot学习之@Configuration注解和@Bean注解
- php解析乱码字符串,PHP substr 截取字符串出现乱码问题解决方法[utf8与gb2312]
- Python之路----------内置函数
- 《数据库SQL实战》查找入职员工时间排名倒数第三的员工的所有信息
- Linux 如何安装 SRPM 包(源代码 rpm 软件包,以 .src.rpm 为后缀名)/rpm 格式的源码软件包/源码包
- 【ElasticSearch】ElasticSearch 7.x 默认不在支持指定索引类型 Failed to parse mapping [_doc]: Root mapping definitio
- 马云乌镇致辞:技术革命最终应该机器更像机器、人更像人
- Android模拟器卡死的解决方案
- 易语言 html邮件,易语言邮件收发源码
- hcna华为认证网络工程师
- 高斯过程回归matlab,高斯过程回归及其应用.PDF
- JAVA实现发短信功能
- JavaWeb-JSON
- 不优雅地解决pytorch模型测试阶段显存溢出问题
- 试戴耳钉会感染艾滋病吗?
- 整理了643个计算机夏令营预推免招生项目,特点如下:
- 《网络安全应急响应技术实战指南》知识点总结(第9章 数据泄露网络安全应急响应)
热门文章
- Vagrant 与 VirtualBox 的保姆级安装教程
- [Java] Appfuse tapestry 小记
- FFmpeg —— 屏幕录像机
- 用户研究|为何这么多用户愿意成为VIP?
- 宾馆客房管理系统设计
- ps4手柄驱动linux,GeForce 344.11正式版驱动:支持GTX 980/970,集成DSR选项
- adobe软件卸载不了怎么办?那就使用dobe官方清理工具吧!
- 企业如何实践开源协同
- 基于java宿舍管理系统的开题报告_基于Java的学生宿舍管理系统开题报告
- Total和Tellurian签署意向性协议,对Driftwood项目和2.5 mtpa LNG进行股权投资;就增加对Tellurian投资签署普通股购买协议