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

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

spring:实例工厂方法获取bean

spring处理使用静态工厂方法获取bean实例&#xff0c;也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下&#xff1a; 定义实例工厂类&#xff08;Java代码&#xff09;&#xff0c;定义实例工厂&#xff08;xml&#xff09;&#xff0c;定义调用实例工厂&#xff…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

如何理解 IP 数据报中的 TTL?

目录 前言理解 前言 面试灵魂一问&#xff1a;说说对 IP 数据报中 TTL 的理解&#xff1f;我们都知道&#xff0c;IP 数据报由首部和数据两部分组成&#xff0c;首部又分为两部分&#xff1a;固定部分和可变部分&#xff0c;共占 20 字节&#xff0c;而即将讨论的 TTL 就位于首…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

Go语言多线程问题

打印零与奇偶数&#xff08;leetcode 1116&#xff09; 方法1&#xff1a;使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

若依登录用户名和密码加密

/*** 获取公钥&#xff1a;前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...