当前位置:网站首页>线程安全的单例模式
线程安全的单例模式
2022-07-03 02:11:00 【abs(ln(1+NaN))】
所谓单例,就是某些类,只能有一个对象
当一个对象被创建出来的时候,首先需要为这个对象开辟空间,然后再调用构造函数来初始化这个对象。然而在单例模式下,这个过程只能出现一次,为了达到这个目的,我们需要满足以下两个条件:
(1) 让内存中仅存在一个对象,这个对象需要类的内部创建,同时使用static修饰(static修饰的变量会放在全局区)
(2) 为了不让类外出现该类的其他对象,我们要将各种构造函数放在private里(如果默认构造、有参构造、拷贝构造用不到,可以使用delete禁用)
目录
一、单例模式的两种情况
在上述的基础上,既然是创建对象,应该什么时候创建呢??这里就分为了两种情况,一种是饿汉方式,一种是懒汉方式。
- 饿汉方式:立马把碗洗干净,方便后面干饭。程序开始运行的时候就把对象创建好
- 懒汉方式:悠哉游哉,等需要时再干饭。等需要用到对象的时候,再主动创建
二、懒汉方式的单例模式
下面以某个单例类为例,这个类使用单例模式中的懒汉方式,也就是等到要使用对象的时候再创建对象,下面就按照上面的两个条件来依次实现。
1、在类内创建对象(要求一)
首先是创建唯一的对象,并用static修饰。唯一的对象在类内部,在类外必然就无法通过下面两种方式来获取
Sington sig; // 错误
Sington* sig = new Sington(); // 错误外部要使用这个对象,肯定是通过类来直接或者间接获取的,既然要通过类来获取,那就需要加上static来修饰

static修饰的成员函数要在类外初始化,初始化的方式类似于类成员函数在类外初始化
变量类型 类名::变量名 = 变量值
2、构造函数私有化或禁用构造函数(要求二)
上面这步只是创建了我们想要的唯一的对象,那么要如何禁止外界创建对象呢??
答案是:将构造函数放在 private 中,或者禁用一部分的构造函数
==》对象在类内被创建的时候,可以调用private里的构造函数;但是如果对象在类外被创建时,public中找不到对应的构造函数,此时就会报错

为什么禁用:假设我们使用获取到的唯一的对象sig 来创建其他对象,内存中Sington类就会有不止一个对象了,这就违背了单例的原则,所以我们要禁用拷贝构造函数
Sington sig1(sig); //拷贝构造函数3、给外部提供获取对象的接口
由于创建出来的对象是放在private中的,类外无法直接访问,所以我们需要给提供一个类外访问的接口,最初版本如下:

但是当有多个线程同时访问这个接口的时候,这个时候存在线程安全问题,我们要保护sig这个临界资源,所以要给临界资源加锁,使用的锁也必须是static修饰的

![]()

现在当一个线程好不容易申请到锁了,但是进去一看,发现 sig 已经被其他线程初始化了,申请锁就显得多此一举,所以我们最好在申请锁之前,再加一道判断,先判断是不是空的,再申请锁。

三、单例模式测试
我们在主线程里创建 5 个线程,每隔1s打印一次当前获取到的对象的地址,以及线程ID

测试结果如下:

四、拓展:饿汉模式(简单介绍)
饿汉模式就是在程序开始运行的时候创建,不同之处在于对象声明方式。
不带*号代表在栈上开辟,这个时候对象在被创建的时候就会被分配空间

在接口函数里,就无需判断是否为空了,直接返回即可

返回值加&的原因是 防止隐式调用拷贝构造函数
边栏推荐
- Network security OpenVAS
- Performance test | script template sorting, tool sorting and result analysis
- stm32F407-------DMA
- easyPOI
- 2022 spring "golden three silver four" job hopping prerequisites: Software Test interview questions (with answers)
- Processing of tree structure data
- Groovy, "try with resources" construction alternative
- [Yu Yue education] reference materials of love psychology of China University of mining and technology
- elastic stack
- Visualisation de l'ensemble de données au format yolov5 (fichier labelme json)
猜你喜欢

通达OA v12流程中心

Depth (penetration) selector:: v-deep/deep/ and > > >

Introduce in detail how to communicate with Huawei cloud IOT through mqtt protocol
![[fluent] fluent debugging (debug debugging window | viewing mobile phone log information | setting normal breakpoints | setting expression breakpoints)](/img/ac/bf83f319ea787c5abd7ac3fabc9ede.jpg)
[fluent] fluent debugging (debug debugging window | viewing mobile phone log information | setting normal breakpoints | setting expression breakpoints)

4. 类和对象

Detailed introduction to the deployment and usage of the Nacos registry

y54.第三章 Kubernetes从入门到精通 -- ingress(二七)

【Camera专题】手把手撸一份驱动 到 点亮Camera

How to deal with cache hot key in redis

深度学习笔记(持续更新中。。。)
随机推荐
How do it students find short-term internships? Which is better, short-term internship or long-term internship?
Modify table structure
人脸识别6- face_recognition_py-基于OpenCV使用Haar级联与dlib库进行人脸检测及实时跟踪
Wechat applet Development Tool Post net:: Err Proxy Connexion Problèmes d'agent défectueux
Network security OpenVAS
stm32F407-------ADC
Leetcode 183 Customers who never order (2022.07.02)
Detailed introduction to the usage of Nacos configuration center
DQL basic operation
Technology sharing | Frida's powerful ability to realize hook functions
Button button adaptive size of wechat applet
详细些介绍如何通过MQTT协议和华为云物联网进行通信
Groovy, "try with resources" construction alternative
Learn BeanShell before you dare to say you know JMeter
《上市风云》荐书——唯勇气最可贵
What are the key points often asked in the redis interview
stm32F407-------ADC
[shutter] shutter debugging (debugging control related functions | breakpoint management | code operation control)
深度(穿透)选择器 ::v-deep/deep/及 > > >
Kotlin middle process understanding and Practice (II)