面试九 设计模式

        单例模式通常被归类为创建型设计模式,因为它主要关注如何创建对象的实例,以及如何确保在整个应用程序生命周期中只有一个实例存在。  

      1.为什么日志模块和数据库连接池需要单例模式

使用单例模式来实现数据库连接池主要有以下几个原因:

  1. 全局唯一性:数据库连接池在应用程序中通常是一个全局资源,多个部分都需要共享同一个连接池。使用单例模式可以确保整个应用程序中只存在一个数据库连接池的实例,避免了资源浪费和连接冲突。

  2. 统一管理:单例模式可以提供一个统一的访问点来管理数据库连接池,使得连接的创建、释放和管理更加方便和可控。

  3. 避免资源竞争:在多线程环境下,如果每次请求都创建一个新的连接池实例,可能会导致资源竞争和线程安全问题。使用单例模式可以避免这种情况,确保连接池的唯一性和线程安全性。

  4. 节省资源:数据库连接池是一种重量级对象,频繁地创建和销毁连接池实例会消耗大量系统资源,而单例模式可以确保连接池的唯一性,节省了系统资源的开销。

  1. 全局唯一性: 日志模块是应用程序中的重要组成部分,通常在整个应用程序中都需要被访问和使用。使用单例模式可以确保在应用程序的生命周期内只存在一个日志模块实例,避免了资源的重复创建和浪费。

  2. 统一管理: 单例模式提供了一个统一的访问点,可以方便地管理日志记录。所有对日志模块的操作都通过单例对象进行,使得管理和维护更加简单和可控。

  3. 避免资源竞争: 在多线程环境下,如果多个线程同时尝试创建日志模块实例,可能会导致资源竞争和线程安全问题。单例模式可以确保在并发情况下只创建一个实例,避免了资源竞争和线程安全性问题。

  4. 节省资源: 日志模块通常是一种重量级对象,频繁地创建和销毁会消耗大量系统资源。使用单例模式可以确保只有一个实例存在,节省了系统资源的开销。

  5. 一致性和可靠性: 使用单例模式可以确保日志记录的一致性和可靠性。由于只有一个日志模块实例存在,所有的日志记录都会经过同一个对象,不会出现不一致或漏掉日志的情况。

 2. 饿汉式单例模式:

        它在类加载时就创建了实例对象,并且在整个程序的生命周期中始终存在。这种方式的单例模式在多线程环境下是线程安全的,因为实例对象在类加载时就已经创建好了,不会出现多个线程同时创建实例的情况。

// 饿汉单例  ,一定是安全的
class Singleton{
public:static Singleton* getInstance(){  // 3. 获取类的唯一实例对象的接口方法return &instance;}private:static Singleton instance;  // 2. 定义一个唯一的类的实例对象Singleton(){  // 1. 构造函数私有化}Singleton(const Singleton&) =delete; //4.禁止拷贝构造  Singleton&  引用类型Singleton& operator= (const Singleton&)=delete; // 5. 禁止赋值函数};
Singleton Singleton::instance; // 在数据段,main函数启动前,已经初始化好了,但是影响启动时间,构造函数用不了,比如加载文件int main(){Singleton *p1 = Singleton::getInstance();std::cout << p1 << std::endl;return 0;
}

3. 懒汉模式

        懒汉式单例模式是一种延迟实例化的单例模式实现方式,在第一次被调用时才会创建实例对象。与饿汉式单例模式不同,懒汉式单例模式的实例对象在需要时才被创建,因此称为"懒汉"。


class Singleton{
public:// 是不是可重入函数? 锁+ 双重判断static Singleton* getInstance(){  // 3. 获取类的唯一实例对象的接口方法if (instance == nullptr) {std::lock_guard<std::mutex> lock(mutex);/*开辟空间给instance 赋值构造对象*/if (instance == nullptr) {instance = new Singleton();}}return instance;}private:/*volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如 果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。##########################################################################################cpu为了加速访问,会将内存的值拷贝一份到寄存器中,加入volatile*/static Singleton *volatile instance;  // 2. 定义一个唯一的类的实例对象// 用于保护多线程环境下的线程安全static std::mutex mutex;Singleton(){  // 1. 构造函数私有化}Singleton(const Singleton&) =delete; //4.禁止拷贝构造  Singleton&  引用类型Singleton& operator= (const Singleton&)=delete; // 5. 禁止赋值函数};
Singleton*volatile Singleton::instance = nullptr;
std::mutex Singleton::mutex;int main(){Singleton *p1 = Singleton::getInstance();std::cout << p1 << std::endl;return 0;
}
class Singleton{
public:static Singleton* getInstance(){  // 3. 获取类的唯一实例对象的接口方法static Singleton instance;  // 2. 定义一个唯一的类的实例对象// 函数的静态局部变量的初始化,在汇编指令上已经自动添加线程互斥指令了return &instance;}private:Singleton(){}Singleton(const Singleton&) =delete; //4.禁止拷贝构造  Singleton&  引用类型Singleton& operator= (const Singleton&)=delete; // 5. 禁止赋值函数};

3. 可重入函数

        可重入函数是指在多线程环境下能够安全地被多个线程同时调用的函数。具体来说,可重入函数满足以下两个条件之一或两者兼具:

  1. 函数不使用静态变量或全局变量(包括静态局部变量),或者使用这些变量时通过互斥锁或其他同步机制来保护变量的访问。
  2. 函数使用的静态变量或全局变量只读,或者在使用时通过互斥锁或其他同步机制来保护变量的访问。

        在多线程环境下,如果一个函数不满足上述条件之一,那么当多个线程同时调用该函数时,就会出现数据竞争和不确定的行为,导致程序的行为变得不可预测,甚至引发崩溃。 

        编写可重入函数的关键是避免共享可变状态,或者在共享状态时采取适当的同步措施,以确保线程安全性。这可能涉及到使用局部变量而不是静态变量或全局变量,使用线程局部存储(Thread-Local Storage,TLS)等技术来避免共享状态,以及使用互斥锁、信号量、原子操作等同步机制来保护共享状态的访问。       

#include <iostream>
#include <mutex>// 可重入函数示例
int reentrantFunction(int value) {// 局部变量,线程私有,不会造成数据竞争int result = 0;result += value * 2;return result;
}int main() {// 多个线程同时调用可重入函数int result1 = reentrantFunction(5);int result2 = reentrantFunction(10);// 打印结果std::cout << "Result 1: " << result1 << std::endl;std::cout << "Result 2: " << result2 << std::endl;return 0;
}

        

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[自研开源] MyData 数据集成之任务调度模式 v0.7

开源地址&#xff1a;gitee | github 详细介绍&#xff1a;MyData 基于 Web API 的数据集成平台 部署文档&#xff1a;用 Docker 部署 MyData 使用手册&#xff1a;MyData 使用手册 试用体验&#xff1a;http://demo.mydata.work 交流 Q 群&#xff1a;430089673 概述 本…

四、Elasticsearch 进阶

自定义目录 4.1 核心概念4.1.1 索引&#xff08;Index&#xff09;4.1.2 类型&#xff08;Type&#xff09;4.1.3 文档&#xff08;Document&#xff09;4.1.3 字段&#xff08;Field&#xff09;4.1.5 映射&#xff08;Mapping&#xff09;4.1.6 分片&#xff08;Shards&#…

富格林:正视安全平台阻挠亏损

富格林悉知&#xff0c;当前不少投资者都意识到一款正规的平台能够帮助我们阻挠亏损确保安全。因此不少投资者在选择都会参考一些排行榜。但是网上这方面的榜单眼花缭乱&#xff0c;新手投资者可能难以从中挑选到能够帮助我们阻挠亏损确保安全的平台。下面富格林将给大家提供一…

STL_list文档使用介绍与底层代码实现简介

文章目录 list介绍list的使用构造函数&#xff08;constructor&#xff09;迭代器list capacitylist modify&#xff08;修改&#xff09;其他接口函数list迭代器失效问题 list实现基础框架(节点类&#xff09;基础框架&#xff08;迭代器类&#xff09;基础框架&#xff08;链…

docker仓库登录及配置insecure-registries的方法

docker仓库登录及配置insecure-registries的方法 这篇文章主要介绍了docker仓库登录配置insecure-registries的方法,docker客户端如果配置中添加了insecure-registary配置&#xff0c;就不需要在docker 客户端配置上对应证书&#xff0c;如果不配置要在/etc/docker/certs.d/目…

【机器学习300问】39、高斯分布模型如何实现异常检测?

一、异常检测是什么&#xff1f; &#xff08;1&#xff09;举几个例子 ① 信用卡交易异常检测 在信用卡交易数据分析中&#xff0c;如果某个用户的消费习惯通常是小额且本地化消费&#xff0c;那么突然出现一笔大额且跨国的交易就可能被标记为异常。 ② 电机温度异常检测 在电…

常见的几个JVM调优场景

文章目录 调优案例案例1&#xff1a;应对高并发、短生命周期对象的应用案例2&#xff1a;防止频繁Full GC导致延迟案例3&#xff1a;优化服务响应时间&#xff0c;减少停顿时间案例4&#xff1a;监控和诊断内存泄露 一些参数堆内存大小元空间大小垃圾收集器相关参数垃圾收集行为…

spring boot学习第十四篇:使用AOP编程

一、基本介绍 1&#xff0c;什么是 AOP &#xff08;1&#xff09;AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意为&#xff1a;面向切面编程&#xff0c;通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。 &#xff08;2&#xff09;利用 AOP…

流畅的 Python 第二版(GPT 重译)(五)

第九章. 装饰器和闭包 有人对将这个功能命名为“装饰器”的选择提出了一些抱怨。主要的抱怨是该名称与其在 GoF 书中的用法不一致。 名称 decorator 可能更多地归因于其在编译器领域的用法—语法树被遍历并注释。 PEP 318—函数和方法的装饰器 函数装饰器让我们在源代码中“标记…

色环电感的工艺结构原理及选型参数总结

🏡《总目录》 目录 1,概述2,工作原理3,结构特点4,工艺流程4.1,磁芯制备:4.2,线圈绕制:5,选型参数5.1,电感值(L)5.2,电流容量(I)5.3,品质因数(Q)5.4,自谐振频率(SRF)5

windows下常用的DOS命令

DOS&#xff08;Disk Operating System&#xff09;是 Windows 操作系统中的命令行接口&#xff0c;也可以叫命令行窗口。一提到这个&#xff0c;很多初入行计算机的朋友们就是很犯怵&#xff0c;不知所错&#xff0c;好高端&#xff0c;有没有。界面如下&#xff1a; 普通用户…

【小程序开发】出行 API 汇总(一)

ty.outdoor.openOutdoorCyclingNavigation 跳转骑行导航页面 引入 import { openOutdoorCyclingNavigation } from ray-js/ray; 注意&#xff1a;当前功能仅在智慧出行App开通使用&#xff0c;需要在基础库2.15.14及以上版本使用。 参数 Object object 属性类型默认值必填…

分享一些关于在实施面试过程被问到的问题

1&#xff0c;说说你对行业现状和发展趋势的看法 一、行业现状&#xff1a; 技术创新&#xff1a;科技行业在近年来取得了显著的技术突破&#xff0c;包括人工智能、大数据、云计算、物联网等领域的发展。这些技术的创新为各行各业带来了前所未有的变革。竞争激烈&#xff1a;…

ARM与X86架构的简单剖析与未来展望

引言 在计算机硬件领域&#xff0c;ARM和X86架构无疑是两种最具影响力的处理器架构。它们各自在全球范围内应用于广泛的设备中&#xff0c;从嵌入式系统到服务器&#xff0c;再到个人电脑和移动设备&#xff0c;塑造了现代计算技术的面貌。本文将深入解析ARM与X86架构的异同&am…

【样式】Html 卡片样式

【样式】Html 卡片样式 .card {width: calc(40% - 10px);height: 160px;display: inline-block; /* 或者 flex / block 根据布局需求 */position: relative;margin: 10px; /* 添加边距以确保卡片之间有间距 */padding: 15px; /* 内边距为内容提供空间 */background-color: rgba…

【Python爬虫】将某网页中表格里的十六进制颜色值转换成十进制,再生成新表格

【需求】 在 https://www.cnblogs.com/heyang78/p/5712076.html 上有360种颜色及代码&#xff0c;但很遗憾没有十进制的RGB值&#xff0c;使用时需要自己转换一下&#xff0c;此过程依赖网络或计算器&#xff0c;颇为不便。因此&#xff0c;拟设计一爬虫将原有表格内容取出&am…

【Linux】初识进程

目录 操作系统是什么 设计操作系统的目的 操作系统的定位 如何理解管理 管理的本质 管理的例子 计算机的管理概念图 操作系统管理逻辑的六字真言 系统调用和库函数的概念 进程 进程的概念 什么是PCB&#xff1f; PCB的主要内容 如何查看进程&#xff1f; 通过系统…

NO9 蓝桥杯单片机实践之串口通信的使用

1 回顾 串口通信的代码编写结构还是与中断一样&#xff0c;不同的是&#xff1a; 初始中断函数条件涉及到串口通信相关的寄存器和定时器1相关的寄存器&#xff08;定时器1用于产生波特率&#xff09;&#xff0c;但初始条件中的中断寄存器只考虑串口通信而不考虑定时器1。 vo…

CMake笔记之将任意官方库作为third_party完整地包含在工程项目中使用的通用模板

CMake笔记之将任意官方库作为third_party完整地包含在工程项目中使用的通用模板 —— 杭州 2024-03-20 凌晨1:06 code review! 文章目录 CMake笔记之将任意官方库作为third_party完整地包含在工程项目中使用的通用模板1.通用CMakeLists.txt模板2.GPT4给出的改进建议3.git clon…

spring boot整合elasticsearch实现查询功能

第一步、添加依赖&#xff08;注意版本对应关系&#xff09;根据spring boot版本选择合适的版本 <dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.6.2</version></dependenc…