线程安全的单例模式

所谓单例,就是某些类,只能有一个对象

当一个对象被创建出来的时候,首先需要为这个对象开辟空间,然后再调用构造函数来初始化这个对象。然而在单例模式下,这个过程只能出现一次,为了达到这个目的,我们需要满足以下两个条件

(1) 让内存中仅存在一个对象,这个对象需要类的内部创建,同时使用static修饰(static修饰的变量会放在全局区)               

(2) 为了不让类外出现该类的其他对象,我们要将各种构造函数放在private里(如果默认构造、有参构造、拷贝构造用不到,可以使用delete禁用)


目录

一、单例模式的两种情况

二、懒汉方式的单例模式

1、在类内创建对象(要求一)

 2、构造函数私有化或禁用构造函数(要求二)

3、给外部提供获取对象的接口

 三、单例模式测试

 四、拓展:饿汉模式(简单介绍)


一、单例模式的两种情况

在上述的基础上,既然是创建对象,应该什么时候创建呢??这里就分为了两种情况,一种是饿汉方式,一种是懒汉方式。

- 饿汉方式:立马把碗洗干净,方便后面干饭。程序开始运行的时候就把对象创建好

- 懒汉方式:悠哉游哉,等需要时再干饭。等需要用到对象的时候,再主动创建

二、懒汉方式的单例模式

下面以某个单例类为例,这个类使用单例模式中的懒汉方式,也就是等到要使用对象的时候再创建对象,下面就按照上面的两个条件来依次实现。

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

 测试结果如下:

 

 四、拓展:饿汉模式(简单介绍)

饿汉模式就是在程序开始运行的时候创建,不同之处在于对象声明方式。

不带*号代表在栈上开辟,这个时候对象在被创建的时候就会被分配空间

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

 返回值加&的原因是 防止隐式调用拷贝构造函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值