当前位置: 首页 > news >正文

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

文章目录

  • 1. 单例模式 与 设计模式
    • 1.1 单例模式
    • 1.2 设计模式
    • 1.3 饿汉实现模式 与 懒汉实现模式
    • 1.4 饿汉模式
      • ① 饿汉模式的特点
      • ② 饿汉式单例模式的实现
      • ③ 饿汉式单例模式的优缺点
      • ④ 适用场景
    • 1.5 懒汉模式
      • ① 懒汉式单例模式的特点
      • ② 懒汉式单例模式的实现
      • ③ 懒汉式单例模式的优缺点
      • ④ 适用场景
  • 2. 智能指针 与 线程安全
    • 2.1 STL的容器是否是线程安全?
    • 2.2 智能指针是否是线程安全?

1. 单例模式 与 设计模式

1.1 单例模式

单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类在整个应用程序中只有一个实例,并提供一个全局访问点来访问这个实例。这个模式适用于那些只需要一个实例来控制整个系统的场景,如配置管理、日志记录等。

关键特性:

  • 唯一性:确保类只有一个实例,避免多实例带来的资源浪费和状态不一致。
  • 全局访问:提供一个全局访问点,使得应用程序中的所有代码能够方便地访问这个唯一实例。
  • 延迟实例化:实现延迟实例化,即仅在第一次访问时创建实例,从而节省资源并提高启动效率。

典型实现(线程安全的单例模式):

class Singleton {
public:static Singleton& getInstance() {static Singleton instance; // 局部静态变量保证实例唯一性return instance;}// 删除拷贝构造函数和赋值运算符以防止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:Singleton() {} // 私有构造函数以防止外部创建实例
};

1.2 设计模式

设计模式(Design Pattern)是面向对象设计中的一种标准化、经过验证的解决方案,用于解决常见的设计问题。

设计模式的类型

  1. 创建型模式:关注对象的创建过程。常见的有:

    • 单例模式(Singleton)
    • 工厂模式(Factory Method)
    • 抽象工厂模式(Abstract Factory)
    • 原型模式(Prototype)
    • 建造者模式(Builder)
  2. 结构型模式:关注类和对象如何组合成更大的结构。常见的有:

    • 适配器模式(Adapter)
    • 装饰器模式(Decorator)
    • 代理模式(Proxy)
    • 桥接模式(Bridge)
    • 组合模式(Composite)
    • 外观模式(Facade)
    • 享元模式(Flyweight)
  3. 行为型模式:关注对象之间的交互和责任分配。常见的有:

    • 观察者模式(Observer)
    • 策略模式(Strategy)
    • 状态模式(State)
    • 责任链模式(Chain of Responsibility)
    • 迭代器模式(Iterator)
    • 访问者模式(Visitor)
    • 模板方法模式(Template Method)
    • 命令模式(Command)
    • 解释器模式(Interpreter)
    • 中介者模式(Mediator)
    • 备忘录模式(Memento)

设计模式的目的:

  • 提高代码复用:通过采用通用的解决方案,减少代码重复,提高复用性。
  • 提高代码可维护性:设计模式提供了清晰的结构,使得代码更易于理解和维护,提升了整体可维护性。
  • 解决常见问题:设计模式为常见的设计问题提供了经过验证的解决方案,帮助开发人员更高效地解决问题。

1.3 饿汉实现模式 与 懒汉实现模式

单例模式分为饿汉实现 与 懒汉实现两种,简单举个例子:

饿汉方式:吃完饭,立刻洗碗;下一顿吃的时候可以立刻拿着碗就能吃饭.(确保资源随时可以使用)
懒汉方式:吃完饭, 先把碗放下, 然后下一顿饭用到这个碗了再洗碗(节省了不必要的操作,优化速度)

接下来我们对这两种单例实现模式进行解释:


1.4 饿汉模式

饿汉模式 在类被加载时就立即创建实例,而不是在第一次需要实例时才创建。这种方式的特点是实例创建时机早,通常用于资源不多且创建实例开销较小的情况。


① 饿汉模式的特点

  1. 立即实例化:类加载时就创建单例实例,不管是否有其他地方需要这个实例。
  2. 线程安全:由于实例在类加载时就创建好了,线程安全问题得到了天然的解决。
  3. 浪费资源:如果单例对象的创建开销较大,而实际运行时不一定会使用这个实例,则会浪费资源。

② 饿汉式单例模式的实现

下面是饿汉实现的单例模式的示例( C++ ):

class Singleton {
public:// 提供全局访问点static Singleton& getInstance() {return instance; // 直接返回已经创建好的实例}// 删除拷贝构造函数和赋值运算符以防止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:// 构造函数是私有的,以防止外部创建实例Singleton() {}// 静态成员变量,类加载时就创建实例static Singleton instance;
};// 在类外定义静态成员变量
Singleton Singleton::instance;

③ 饿汉式单例模式的优缺点

优点:

  • 线程安全:由于实例在程序启动时即被创建,因此不需要额外的同步机制来确保线程安全。
  • 简单易用:实现过程简单,易于理解和使用。

缺点:

  • 资源浪费:即使在程序运行过程中不需要这个单例实例,也会在启动时创建,可能导致资源浪费。
  • 不适合大开销对象:对于实例化开销较大的对象,预创建可能导致不必要的资源消耗。

④ 适用场景

  • 实例化对象开销较小且必定会被使用。
  • 对线程安全要求较高,且不介意在应用启动时立即创建实例。

1.5 懒汉模式

懒汉模式(Lazy Initialization) 是一种单例模式的实现方式,它在第一次需要实例时才创建对象。这种方式的特点是推迟实例化,从而避免不必要的资源消耗。

① 懒汉式单例模式的特点

  • 延迟实例化:对象仅在第一次被请求时才进行创建,从而提高了程序的效率。
  • 资源节省:在不需要实例的情况下,避免了资源的浪费,优化了资源使用。
  • 线程安全问题:在多线程环境下,可能需要额外的同步机制来确保线程安全,确保实例的唯一性。

② 懒汉式单例模式的实现

下面是懒汉模式的实现( C++ ):

#include <mutex>class Singleton {
public:// 提供全局访问点static Singleton* getInstance() {if (!instance) { // 如果实例尚未创建std::lock_guard<std::mutex> guard(mutex); // 加锁if (!instance) { // 再次检查以避免多线程下的重复创建instance = new Singleton(); // 创建实例}}return instance;}// 删除拷贝构造函数和赋值运算符以防止复制Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;private:// 构造函数是私有的,以防止外部创建实例Singleton() {}// 静态成员变量,保存单例实例static Singleton* instance;// 互斥锁,保护实例化过程static std::mutex mutex;
};// 在类外定义静态成员变量
Singleton* Singleton::instance = nullptr;
std::mutex Singleton::mutex;

③ 懒汉式单例模式的优缺点

优点:

  • 节省资源:实例仅在实际需要时创建,从而避免了不必要的资源消耗。
  • 延迟加载:能够提升程序启动速度,尤其在创建单例对象开销较大的情况下尤为显著。

缺点:

  • 线程安全问题:在多线程环境下,可能需要额外的同步机制,如使用互斥锁(mutex),以避免竞态条件。
  • 实现复杂度:比起饿汉式单例实现更复杂,需要处理多线程环境下的同步问题。

④ 适用场景

  • 实例化开销较大或不一定需要使用实例时。
  • 需要延迟加载,优化资源使用。

2. 智能指针 与 线程安全

2.1 STL的容器是否是线程安全?

不是!

  1. STL 的设计初衷是尽可能的利用性能,进行高效的编码,一旦涉及到加锁保证线程安全, 会对性能造成巨大的影响.
  2. 对于不同的容器,加锁方式的不同,性能可能也不同(如hash表的锁表和锁桶)
  3. 因此 STL 默认不是线程安全. 如果需要在多线程环境下使用, 往往需要调用者自行保证线程安全

2.2 智能指针是否是线程安全?

  • 对于 unique_ptr,其只在当前代码块范围内生效, 因此不涉及线程安全问题.
  • 对于 shared_ptr, 多个对象需要共用一个引用计数变量,存在线程安全问题,但标准库实现时考虑到了该问题,基于原子操作(CAS)的方式保证 shared_ptr 能够高效, 原子的操作引用计数

相关文章:

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

文章目录 1. 单例模式 与 设计模式1.1 单例模式1.2 设计模式1.3 饿汉实现模式 与 懒汉实现模式1.4 饿汉模式① 饿汉模式的特点② 饿汉式单例模式的实现③ 饿汉式单例模式的优缺点④ 适用场景 1.5 懒汉模式① 懒汉式单例模式的特点② 懒汉式单例模式的实现③ 懒汉式单例模式的优…...

基于jqury和canvas画板技术五子棋游戏设计与实现(论文+源码)_kaic

摘 要 网络五子棋游戏如今面临着一些新的挑战和机遇。一方面&#xff0c;网络游戏需要考虑到网络延迟和带宽等因素&#xff0c;保证游戏的实时性和稳定性。另一方面&#xff0c;网络游戏需要考虑到游戏的可玩性和趣味性&#xff0c;以吸引更多的玩家参与。本文基于HTML5和Canv…...

指针 (四)

一 . 指针的使用和传值调用 &#xff08;1&#xff09;strlen 的模拟实现 库函数 strlen 的功能是求字符串长度&#xff0c;统计的是字符串中 \0 之前的字符个数&#xff0c;函数原格式如下&#xff1a; 我们的参数 str 接收到一个字符串的起始地址&#xff0c;然后开始统计…...

便利店(超市)管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图详细视频演示技术栈系统测试为什么选择我官方认证玩家&#xff0c;服务很多代码文档&#xff0c;百分百好评&#xff0c;战绩可查&#xff01;&#xff01;入职于互联网大厂&#xff0c;可以交流&#xff0c;共同进步。有保障的售后 代码参考数据库参…...

Excel中的“块”操作

在Excel中&#xff0c;有offset、index、indirect三个对“区域”操作的函数&#xff0c;是较高版本Excel中“块”操作的利器。 (笔记模板由python脚本于2024年08月20日 19:25:21创建&#xff0c;本篇笔记适合喜欢用Excel处理数据的coder翻阅) 【学习的细节是欢悦的历程】 Pytho…...

yolo V8训练 长条状目标

1、说明 目标数据集合中有很多长条状图片&#xff0c;如果直接Resize 会严重拉伸&#xff0c;因此采用把长条图像裁剪成2段&#xff0c;然后将裁剪后的2段图片拼接在一起。 2、代码 2.1 C 代码 &#xff08;部署&#xff0c;模型推理时C &#xff09; #include <stdio.h…...

数据结构与算法 - 设计

1. LRU缓存 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0…...

62 网络设备的暗藏的操控者SNMP

一 SNMP 简介 SNMP(Simple Network Management Protocol,简单网络管理协议)广泛用于网络设备的远程管理和操作。SNMP允许管理员通过NMS对网络上不同厂商、不同物理特性、采用不同互联技术的设备进行管理,包括状态监控、数据采集和故障处理。 二 SNMP 网络架构 NMS(Netwo…...

华硕飞行堡垒键盘全部失灵【除电源键】

华硕飞行堡垒FX53VD键盘全部失灵【除电源键】 前言一、故障排查二、发现问题三、使用方法总结 前言 版本型号&#xff1a; 型号 ASUS FX53VD&#xff08;华硕-飞行堡垒&#xff09; 板号&#xff1a;GL553VD 故障情况描述&#xff1a; 键盘无法使用&#xff0c;键盘除开机键外…...

前端字符串将其分割成长度为 32 的子字符串数组

技巧分享&#xff1a;将字符串切割后&#xff0c;对list数据进行数据处理 要实现这个需求&#xff0c;可以编写一个简单的 JavaScript 函数来处理字符串并将其分割成长度为 32 的子字符串数组。下面是一个具体的实现示例&#xff1a; function splitStringIntoChunks(str) {l…...

小学二年级数学精选试题

小学二年级数学精选试题...

练习题 - 探索正则表达式re功能

在编程的世界里,正则表达式(Regular Expression, 简称re)是一种强大的工具,它能帮助我们有效地处理文本数据。从简单的查找到复杂的字符串操作,正则表达式都能轻松应对。特别是在数据清理、文本分析以及自动化处理等场景中,正则表达式更是不可或缺的利器。本篇文章将深入…...

【Oracle 11G 配置使用教程1】

Oracle11G配置使用教程1 引言图像方式创建数据库一、打开 Database Configuration Assistant二、创建数据库操作三、选择数据库模版四、配置数据库标识五、配置数据库标识六、创建数据库 配置监听一、打开创建监听程序二、打开创建监听程序三、重新配置监听程序四、选择监听程序…...

【ubuntu24.04】docker pull 配置

Docker 镜像加速器 的方式,看起来不行。阿里云的要先登录。手动拉取tar包的方式,官方dockerhub看起来本身没提供。docker pull 的 代理与 环境变量的代理不同因此,docker pull gitlab/gitlab-ce:17.3.0-ce.0 使用了全局代理也会失败参考官方文档: Use a proxy server with …...

《机器学习》—— 通过下采样方法实现银行贷款分类问题

文章目录 一、什么是下采样方法&#xff1f;二、通过下采样方法实现银行贷款分类问题三、下采样的优缺点 一、什么是下采样方法&#xff1f; 机器学习中的下采样&#xff08;Undersampling&#xff09;方法是一种处理不平衡数据集的有效手段&#xff0c;特别是在数据集中某些类…...

Synchronized重量级锁原理和实战(五)

在JVM中,每个对象都关联这一个监视器,这里的对象包含可Object实例和Class实例.监视器是一个同步工具,相当于一个凭证,拿到这个凭证就可以进入临界区执行操作,没有拿到凭证就只能阻塞等待.重量级锁通过监视器的方式保证了任何时间内只允许一个线程通过监视器保护的临界区代码. …...

linux常用网络工具汇总三

linux常用网络工具汇总 6. 抓包工具6.1 wireshark安装界面介绍使用过滤器TCP协议示例关于wireshark的缺点 6.2 tcpdump命令格式关键字使用关于tcpdump的缺点 6.3 fiddler6.4 burpsuite 6. 抓包工具 6.1 wireshark Wireshark&#xff08;前称Ethereal&#xff09;是一个网络封…...

Linux中nano编辑器详解

nano 是一个简单的文本编辑器&#xff0c;通常预装在大多数 Linux 发行版中。它非常适合初学者使用&#xff0c;因为它有一个用户友好的界面和易于理解的命令集。下面是对 nano 编辑器的详细说明。 启动 nano 要启动 nano 并打开一个文件进行编辑&#xff0c;你可以在终端中输…...

26-vector arraylist和linkedlist的区别

‌Vector, ArrayList, 和 LinkedList 是Java中常见的三种列表实现&#xff0c;它们各自具有不同的特点和适用场景。‌ ‌同步性与线程安全‌&#xff1a; ‌Vector‌ 是同步的&#xff0c;即线程安全的&#xff0c;它的所有方法都是同步的&#xff0c;可以由两个线程安全地访问…...

20-redis穿透击穿雪崩

Redis中的缓存穿透、‌缓存击穿和缓存雪崩是三种常见的缓存问题&#xff1a;‌ 缓存穿透&#xff1a;‌指缓存和数据库中都没有的数据&#xff0c;‌但用户还是源源不断地发起请求&#xff0c;‌导致每次请求都会直接访问数据库&#xff0c;‌从而可能压垮数据库。‌缓存击穿&…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销&#xff0c;平衡网络负载&#xff0c;延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

Objective-C常用命名规范总结

【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名&#xff08;Class Name)2.协议名&#xff08;Protocol Name)3.方法名&#xff08;Method Name)4.属性名&#xff08;Property Name&#xff09;5.局部变量/实例变量&#xff08;Local / Instance Variables&…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...