当前位置: 首页 > 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;‌从而可能压垮数据库。‌缓存击穿&…...

Docker使用教程

Docker 名词解释 镜像&#xff08;image&#xff09;&#xff1a;Docker镜像就是一个模板&#xff0c;可以通过这个模板来创建容器服务。容器&#xff08;container&#xff09;&#xff1a;Docker利用容器技术&#xff0c;独立运行一个或者一组应用&#xff0c;通过镜像创建…...

poi-tl循环放图片+文字说明

这几天有个任务&#xff0c;服务端导出word要求从数据库取到多张图片&#xff0c;然后输出到word中&#xff0c;并且说明一共几张&#xff0c;当前是第几张。 网上翻了很久也没有找到示例&#xff0c;不过最终难题还是得到了攻克。 因为之前的代码是有一个导出的map&#xff0c…...

数据结构之树的存储结构

一、顺序存储结构 顺序存储结构通常用于表示完全二叉树。在这种存储方式中&#xff0c;树中的节点被存储在一个连续的数组中。对于完全二叉树&#xff0c;如果父节点的索引是i&#xff08;假设从0开始计数&#xff09;&#xff0c;那么它的左子节点的索引是2i1&#xff0c;右子…...

Zotero 常用插件介绍

1. Zotero 插件安装方法 下载以 .xpi 结尾的插件&#xff1b;打开 Zotero → 工具 → 插件 → 右上小齿轮图标 → Install Add-on From File ... → 选择下载好的 .xpi 插件安装 → 重启 Zotero 2. 常用插件介绍 2.1. Scholaread - 靠岸学术 Zotero 英文文献相关插件&#xf…...

WebSocket协议解析

文章目录 一、HTTP协议与HTTPS协议1.HTTP协议的用处2.HTTP协议的特点3.HTTP协议的工作流程4.HTTPS协议的用处5.HTTPS协议的特点6.HTTPS协议的工作流程 二、WebSocket协议出现的原因1. 传统的HTTP请求-响应模型2. 轮询&#xff08;Polling&#xff09;3. 长轮询&#xff08;Long…...

ES6 (一)——ES6 简介及环境搭建

目录 简介 环境搭建 可以在 Node.js 环境中运行 ES6 webpack 入口 (entry) loader 插件 (plugins) 利用 webpack 搭建应用 gulp 如何使用&#xff1f; 简介 ES6&#xff0c; 全称 ECMAScript 6.0 &#xff0c;是 JavaScript 的下一个版本标准&#xff0c;2015.06 发版…...

HarmonyOS开发案例:列表场景实例-TaskPool

介绍 本实例通过列表场景实例讲解&#xff0c;介绍在TaskPool线程中操作关系型数据库的方法&#xff0c;涵盖单条插入、批量插入、删除和查询操作。 效果图预览 使用说明 进入页面有insert(单条数据插入)、batch insert(批量数据插入)、query(查询操作)三个按钮&#xff0c;…...

谷歌浏览器如何隐藏书签

谷歌浏览器的书签栏是一个极为方便的功能&#xff0c;它能够帮助用户快速访问自己频繁使用的网页。然而&#xff0c;有些时候为了保护个人隐私或使浏览界面更为简洁&#xff0c;我们可能需要隐藏书签栏。接下来就为大家分享如何隐藏谷歌浏览器的书签栏&#xff0c;一起来看看吧…...

SQL - 视图

我们可以把查询或子查询存到视图里&#xff0c;视图的作用就像一张虚拟表&#xff0c;再次查询时&#xff0c;就不需要再写一次复杂的查询。创建视图 create view 视图名 as (查询); create or replace view clients_balance as (查询); create or replace view clients_balanc…...

centos7环境升级默认的gcc 4.8.5到gcc 8.2.0, 并且升级glibc到glibc 2.28

这里写目录标题 makegccglibc make #下载 wget http://ftp.gnu.org/gnu/make/make-4.2.tar.gz tar -xf make-4.2.tar.gz cd make-4.2 ./configure make -j4 make install mv /usr/bin/make /usr/bin/make_bak cp ./make /usr/bin/make -v GNU Make 4.2 Built for x86_64-pc-li…...