【Linux】:线程安全的单例模式

线程安全的单例模式

  • 一.STL和智能指针的安全
  • 二.单例模式
    • 1.基本概念
    • 2.懒汉和饿汉的实现方式
  • 三.常见的其它锁
  • 四.读者写者模型

一.STL和智能指针的安全

1.STL中的容器是否是线程安全的?

不是. 原因是, STL 的设计初衷是将性能挖掘到极致, 而一旦涉及到加锁保证线程安全, 会对性能造成巨大的影响.而且对于不同的容器,加锁方式的不同, 性能可能也不同(例如hash表的锁表和锁桶).因此 STL 默认不是线程安全. 如果需要在多线程环境下使用,往往需要调用者自行保证线程安全。

2.智能指针是否是线程安全的?

对于 unique_ptr, 由于只是在当前代码块范围内生效, 因此不涉及线程安全问题.

对于 shared_ptr, 多个对象需要共用一个引用计数变量, 所以会存在线程安全问题. 但是标准库实现的时候考虑到了这个问题, 基于原子操作(CAS)的方式保证 shared_ptr 能够高效, 原子的操作引用计数.

二.单例模式

1.基本概念

1.什么是单例模式

单例模式是一种 “经典的, 常用的, 常考的” 设计模式。

2.单例模式的特点

某些类, 只应该具有一个对象(实例), 就称之为单例。

3.单例模式常见的两种设计方式

饿汉方式和懒汉方式。

举个例子:

吃完饭, 立刻洗碗, 这种就是饿汉方式. 因为下一顿吃的时候可以立刻拿着碗就能吃饭.
吃完饭, 先把碗放下, 然后下一顿饭用到这个碗了再洗碗, 就是懒汉方式.

换言之,当我们申请空间时,饿汉是立马申请;懒汉是延时申请(当我们真的需要使用时再申请)。懒汉的优势在于可以提高我们的运行速度,因为它把申请空间的所需的时间延后了,所以我们当前运行就会变快。再例如打开一个游戏,10个G,懒汉先加载要使用的,剩下的等需要时再加载,这样游戏的运行速度变快了。

2.懒汉和饿汉的实现方式

伪代码

在这里插入图片描述

两者的主要区别在于,一个是直接创建对象,一个是先创建的对象指针,等需要时再new一个对象。static修饰的是静态变量,也是全局变量的一种,也就意味着饿汉是在程序加载到内存时就要创建对象,而懒汉不需要,所以懒汉提高了运行效率。

懒汉模式的线程安全问题

很明显,在进行多并发时,懒汉模式会存在安全问题。当一个线程判断完if后,正准备new对象,结果就被替换了,接着又来一个线程进行if判断也能通过,这样就造成了new了多个对象。解决方法也很简单,在if前面加锁就行了。进一步优化一下:当第一个对象被new出来后,其实就不再需要锁了,这样重复的加锁,解锁也会对性能造成影响,所以再在锁的前面套一个if判断,下面是优化版本。

在这里插入图片描述

三.常见的其它锁

  1. 悲观锁:在每次取数据时,总是担心数据会被其他线程修改,所以会在取数据前先加锁(读锁,写锁,行锁等),当其他线程想要访问数据时,被阻塞挂起。
  2. 乐观锁:每次取数据时候,总是乐观的认为数据不会被其他线程修改,因此不上锁。但是在更新数据前,会判断其他数据在更新前有没有对数据进行修改。主要采用两种方式:版本号机制和CAS操作。
  3. CAS操作:当需要更新数据时,判断当前内存值和之前取得的值是否相等。如果相等则用新值更新。若不等则失败,失败则重试,一般是一个自旋的过程,即不断重试。

自旋锁:

这个锁与之前的锁有些区别,之前的锁都称作挂起等待锁,顾名思义就是获取锁失败后把自己挂起。但该锁不一样,它获取锁失败后不让自己挂起,而由线程周而复始的去申请锁,在申请锁的过程中不断检测锁的状态的过程就叫做自旋。

很明显,这个过程是消耗时间的,所以使用自旋锁一般在临界资源释放时间很短的情况下使用。

在这里插入图片描述

第一个函数申请锁失败后会直接挂起,而第二个函数申请锁失败后会返回失败。所以实现一个自旋锁直接用第二个函数再外加一个while循环即可。

当然,pthread库直接提供了自旋锁的接口。

在这里插入图片描述
自旋锁阻塞版本也并不是挂起,实际上就是底层封装了while循环,当申请锁失败后一直循环,看到的效果就是阻塞了。非阻塞版本就是没有封装while。

当然该锁也有初始化,解锁,销毁…与互斥锁基本一致。

总结:对于用户而言,自旋锁#其它锁区别在于一个不会将线程挂起,一个会挂起罢了。

四.读者写者模型

在这里插入图片描述

读写锁

在编写多线程的时候,有一种情况是十分常见的。那就是,有些公共数据修改的机会比较少。相比较改写,它们读的机会反而高的多。通常而言,在读的过程中,往往伴随着查找的操作,中间耗时很长。给这种代码段加锁,会极大地降低我们程序的效率。那么有没有一种方法,可以专门处理这种多读少写的情况呢? 有,那就是读写锁。

在这里插入图片描述

加锁:读者加锁和写者加锁是不同的

写者。

在这里插入图片描述

读者。

在这里插入图片描述

在这里插入图片描述

读写者模型有一个特点:读者优先。因为读者的数量一般情况下是远远大于写者的,所以在竞争锁时,读者有更大的概率得到锁,可能会导致写者一直得不到锁,从而造成线程饥饿问题。注意:这里的线程饥饿是一个中性词,因为这本是它的特点。当然我们也可以通过修改代码来实现写者优先。

为了更好的理解,下面是伪代码

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/352896.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[SwiftUI]系统弹窗和自定义弹窗

一、系统弹窗 在 SwiftUI 中,.alert 是一个修饰符,用于在某些条件下显示一个警告对话框。Alert 可以配置标题、消息和一系列的按钮。每个按钮可以是默认样式、取消样式,或者是破坏性的样式,它们分别对应不同的用户操作。 1.Aler…

Spring 的存储和获取Bean

文章目录 获取 Spring 上下文对象的方式存储 Bean 对象的方式类注解配置扫描路径(必须)Controller(控制器存储)Service(服务)Repository(持久层)Component(工具&#xff…

【Spring】Spring简介、IOC、DI

目录 Spring简介 Spring Framework五大功能模块 IOC容器 IOC思想 IOC容器在Spring中的实现 基于XML管理bean 配置bean 获取bean 依赖注入之setter注入 依赖注入之构造器注入 特殊值处理 字面量赋值 null值 xml实体 CDATA节 为类类型属性赋值 为数组类型属性赋值 为集合类型属性…

JavaScript 学习笔记(JS进阶 Day1)

「写在前面」 本文为 b 站黑马程序员 pink 老师 JavaScript 教程的学习笔记。本着自己学习、分享他人的态度,分享学习笔记,希望能对大家有所帮助。推荐先按顺序阅读往期内容: 1. JavaScript 学习笔记(Day1) 2. JavaSc…

适用于 Windows 11 的 12 个最佳免费 PDF 编辑器

除了绘图等基本功能外,一些适用于 Windows 11 的免费 PDF 编辑器还具有 AI、OCR 识别和书签等高级功能。 我们的列表包含易于立即下载的 PDF 编辑软件工具。 这些工具不仅可以帮助转换 PDF、编辑、上传、删除、裁剪、分割、提取等。 PDF 是指便携式文档格式&…

单片机学习笔记---独立按键控制LED亮灭

直接进入正题! 今天开始我们要学习一个新的模块:独立按键! 先说独立按键的内部结构: 它相当于一种电子开关,按下时开关接通,松开时开关断开,实现原理是通过轻触按键内部的金属弹片受力弹动来实…

剧本杀小程序开发:打造沉浸式推理体验

随着社交娱乐形式的多样化,剧本杀逐渐成为年轻人喜爱的聚会活动。而随着技术的发展,剧本杀小程序的开发也成为了可能。本文将探讨剧本杀小程序开发的必要性、功能特点、开发流程以及市场前景。 一、剧本杀小程序开发的必要性 剧本杀是一种角色扮演的推…

鸿蒙端云一体化简单项目

文章目录 前言端云一体化服务端客户端云数据库总结 一、前言 鸿蒙系统在不断地成熟,现在有了鸿蒙端云一体化开发模式。什么是端云一体化呢,简单点就是你原本是客户端开发的,项目中只是客户端的代码,端云一体化呢,就…

【MyBatis】#{} 和 ${}

目录 1. #{} 使用示例: 2. ${} 使用示例: SQL注入 使用#{}的情况: 使用${}的情况: MyBatis是一种用于Java语言的持久层框架,它简化了数据库操作的过程。在MyBatis中,我们经常会看到两种不同的参数占…

华为云WAF,开启web网站的专属反爬虫防护罩

背景 从保护原创说起 作为一个原创技术文章分享博主,日常除了Codeing就是总结Codeing中的技术经验。 之前并没有对文章原创性的保护意识,直到在某个非入驻的平台看到了我的文章,才意识到,辛苦码字、为灵感反复试验创作出来的文…

苹果macOS 恶意软件家族被曝光:通过破解软件分发,可窃取敏感信息

卡巴斯基安全实验室近日发布博文,发现了一种针对苹果 macOS 设备的新型恶意软件家族,并提醒苹果 Mac 用户谨慎下载破解软件。 报告称这种新型恶意软件家族高度复杂,主要伪装成为各种知名 macOS 软件的破解版分发,用户下载恶意 PKG…

ISO 14229和UDS:汽车诊断的黄金标准

UDS简介: UDS是Unified Diagnostic Services的缩写,全名统一诊断服务。它是一种用于汽车电子控制单元(ECU)之间进行诊断和通信的标准协议,属于ISO 14229标准的一部分。 UDS的起源和背景: UDS的起源可以追…

HarmonyOS 鸿蒙应用开发 (七、HTTP网络组件 axios 介绍及封装使用)

在HarmonyOS应用开发中,通过HTTP访问网络,可以使用官方提供的ohos.net.http模块。但是官方提供的直接使用不太好使用,需要封装下才好。推荐使用前端开发中流行的axios网络客户端库,如果是前端开发者,用 axios也会更加顺…

Java笔记(死锁、线程通信、单例模式)

一、死锁 1.概述 死锁 : 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法往下执行。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进…

vusui css 使用,简单明了 适合后端人员 已解决

vusui-cssopen in new window 免除开发者繁复的手写 CSS 样式,让 WEB 前端开发更简单、灵活、便捷!如果喜欢就点个 ★Staropen in new window 吧。 移动设备优先: vusui-css 包含了贯穿于整个库的移动设备优先的样式。浏览器支持&#xff1a…

【每日一题】最大合金数

文章目录 Tag题目来源解题思路方法一:二分枚举答案 写在最后 Tag 【二分枚举答案】【数组】【2024-01-27】 题目来源 2861. 最大合金数 解题思路 方法一:二分枚举答案 思路 如果我们可以制造 x 块合金,那么一定也可以制造 x-1 块合金。于…

《合成孔径雷达成像算法与实现》Figure5.18

clc clear close all距离向参数 R_eta_c 20e3; % 景中心斜距 Tr 25e-6; % 发射脉冲时宽 Kr 0.25e12; % 距离向调频率 Fr 7.5e6; % 距离向采样率 Nrg 256; % 距离线采样点数 Bw abs(Kr*Tr); …

【C++干货铺】C++中的IO流和文件操作

个人主页点击直达:小白不是程序媛 C系列专栏:C干货铺 代码仓库:Gitee 目录 C语言的输入输出 流是什么? C的IO流 C标准IO流 C文件IO流 文本文件读写 二进制文件的读写 stringstream的简单介绍 将数值类型数据格式化为字…

JS中的try...catch

一、定义和结构 作用:捕获同步执行代码下的异常错误 在没有使用try...catch的情况下,同步代码执行遇到异常会报错,并中断后续代码执行; 在使用try...catch的情况下,同步代码执行遇到异常会抛出异常,并继续…

线性代数----------学习记录

线性代数发展历程 (1)线性方程组:例如二元一次方程组; (2)行列式:determinant,克莱默,莱布尼兹; (3)矩阵:方程个数与未知数的个数可…