单例模式(饿汉模式和懒汉模式)

单例模式也叫单件模式。Singleton是一个非常常用的设计模式,几乎所有稍微大一些的程序都会使用到它,所以构建一个线程安全并且高效的Singleton很重要。
单例模式的特点:
1>单例类保证全局只有一个唯一实例对象。
2>单例类提供获取这个唯一实例的接口。

1.下面先简单设计一个单例模式
这里写图片描述
这里写图片描述
但是这样设计会有线程安全的问题。为什么说这样实现的一个单例模式是线程不安全的呢?是因为暴露给外部接口的函数中_inst=new Singleton;是非原子操作,易出现线程安全问题。
2. 针对线程安全有以下解决方法:
(一)加锁
(二)使非原子操作变为原子的,一般系统会提供一个原子性操作函数(给CPU做一个标记,告诉CPU只要该操作开始执行就不能被切换出去)
下面主要以第一种方式来解决问题!
在Linux下POSIX机制中有lock,unlock等,但在Windows下一般不提供锁机制,使用临界区的形式,但是在C++11库中提供了锁机制。
先引入头文件:#include
定义锁变量:
这里写图片描述
在类外进行初始化:
这里写图片描述
给线程不安全的地方加锁:
这里写图片描述
但是加锁后引来一个性能问题,单例模式的设计我们讲究高效,所以在这基础上还应该优化,可以采取双重检查的方式。
这里写图片描述
上面加锁后又会引发死锁情况,如果在_inst=new Singleton;这里分配空间失败,可能会抛出异常,这时去捕获异常的话就会引发死锁的情况,针对这种情况我们可以用RAII机制去解决,类似于智能指针。
这里写图片描述
这里写图片描述
写好的代码经过编译后为可执行的二进制文件给CPU去执行,CPU可能会优化一些指令,比如:_inst=new Singleton;分为三步去执行:一是分配空间,二是调构造函数,三是赋值。加入双重检查可能会带来的一个问题是CPU对指令优化从而打乱执行顺序导致错误,如果二三步骤颠倒,没有调构造函数前可能为一个随机数或野指针,如果这时赋值,然后这时该线程被切出去,再来一个线程检查它不为0或NULL就直接返回该值导致一些意想不到的问题。我们可以调用windows系统下的函数MemoryBarrier(); //内存栅栏函数来保证下面的tmp是一个完整的对象指针。
这里写图片描述
该种就是最终版的懒汉单例模式(线程安全的且高效).

3.下面再介绍两种饿汉单例模式:
(1)利用静态成员变量初始化在调main函数之前的特性实现,这种方式没有加锁,没有双重检查,也不用考虑异常捕获造成的内存泄漏。
这里写图片描述
这里写图片描述
(2)在调用接口函数获得对象时才临时创建
这里写图片描述

4.饿汉模式用于静态联编没有问题,但是在动态联编会出现问题。
静态编译是将链接库都加载到该目标代码中,但是动态编译是运行起来才将链接文件加载进来,这会儿用饿汉模式可能对象的初始化会存在问题。

5.完整代码已上传至github
Singleton.cpp

Java单例模式包括饿汉式和懒汉式两种实现方式。饿汉式是在类加载阶段就创建实例并持有,而懒汉式则是在需要时才创建实例。 饿汉模式是指在类加载阶段就创建出实例的,因此它的实例化过程相对于普通情况要早很多。这也是为什么叫“饿汉”的原因,就像一个饥饿的人对食物没有抵抗力,一下子就开始吃了一样。 懒汉模式是指在需要时才创建实例。这种方式的优点是节省了资源,只有在需要时才会进行实例化。但是它的缺点是在多线程环境下可能会导致多个线程同时创建实例的问题,需要进行额外的线程安全措施来解决这个问题。 总结来说,饿汉式适合在应用启动时就需要创建实例的情况,因为它的实例化过程早于普通情况。而懒汉式适合在需要时才创建实例的情况,可以节省资源。 需要注意的是,单例模式的使用要根据具体的适应场景来决定,不同的情况下选择不同的实现方式。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Java设计模式单例模式——饿汉式、懒汉式(初了解)](https://blog.csdn.net/m0_68062837/article/details/127307310)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Java多线程案例之单例模式饿汉懒汉)](https://blog.csdn.net/qq_63218110/article/details/128738155)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值