面试九 设计模式
单例模式通常被归类为创建型设计模式,因为它主要关注如何创建对象的实例,以及如何确保在整个应用程序生命周期中只有一个实例存在。
1.为什么日志模块和数据库连接池需要单例模式
使用单例模式来实现数据库连接池主要有以下几个原因:
全局唯一性:数据库连接池在应用程序中通常是一个全局资源,多个部分都需要共享同一个连接池。使用单例模式可以确保整个应用程序中只存在一个数据库连接池的实例,避免了资源浪费和连接冲突。
统一管理:单例模式可以提供一个统一的访问点来管理数据库连接池,使得连接的创建、释放和管理更加方便和可控。
避免资源竞争:在多线程环境下,如果每次请求都创建一个新的连接池实例,可能会导致资源竞争和线程安全问题。使用单例模式可以避免这种情况,确保连接池的唯一性和线程安全性。
节省资源:数据库连接池是一种重量级对象,频繁地创建和销毁连接池实例会消耗大量系统资源,而单例模式可以确保连接池的唯一性,节省了系统资源的开销。
全局唯一性: 日志模块是应用程序中的重要组成部分,通常在整个应用程序中都需要被访问和使用。使用单例模式可以确保在应用程序的生命周期内只存在一个日志模块实例,避免了资源的重复创建和浪费。
统一管理: 单例模式提供了一个统一的访问点,可以方便地管理日志记录。所有对日志模块的操作都通过单例对象进行,使得管理和维护更加简单和可控。
避免资源竞争: 在多线程环境下,如果多个线程同时尝试创建日志模块实例,可能会导致资源竞争和线程安全问题。单例模式可以确保在并发情况下只创建一个实例,避免了资源竞争和线程安全性问题。
节省资源: 日志模块通常是一种重量级对象,频繁地创建和销毁会消耗大量系统资源。使用单例模式可以确保只有一个实例存在,节省了系统资源的开销。
一致性和可靠性: 使用单例模式可以确保日志记录的一致性和可靠性。由于只有一个日志模块实例存在,所有的日志记录都会经过同一个对象,不会出现不一致或漏掉日志的情况。
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. 可重入函数
可重入函数是指在多线程环境下能够安全地被多个线程同时调用的函数。具体来说,可重入函数满足以下两个条件之一或两者兼具:
- 函数不使用静态变量或全局变量(包括静态局部变量),或者使用这些变量时通过互斥锁或其他同步机制来保护变量的访问。
- 函数使用的静态变量或全局变量只读,或者在使用时通过互斥锁或其他同步机制来保护变量的访问。
在多线程环境下,如果一个函数不满足上述条件之一,那么当多个线程同时调用该函数时,就会出现数据竞争和不确定的行为,导致程序的行为变得不可预测,甚至引发崩溃。
编写可重入函数的关键是避免共享可变状态,或者在共享状态时采取适当的同步措施,以确保线程安全性。这可能涉及到使用局部变量而不是静态变量或全局变量,使用线程局部存储(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;
}
相关文章:
面试九 设计模式
单例模式通常被归类为创建型设计模式,因为它主要关注如何创建对象的实例,以及如何确保在整个应用程序生命周期中只有一个实例存在。 1.为什么日志模块和数据库连接池需要单例模式 使用单例模式来实现数据库连接池主要有以下几个原因: 全局唯…...
c++和c语言的区别实例
C和C语言在程序设计领域内具有深远的影响,它们不仅丰富了编程的世界,也为软件开发人员提供了强大的工具。虽然C是在C语言的基础上发展起来的,但两者之间存在着一些关键的区别。为了更深入地理解这些不同,本文将从多个维度探讨C和C…...

图论基础|841.钥匙和房间、463. 岛屿的周长
目录 841.钥匙和房间 思路:本题是一个有向图搜索全路径的问题。 只能用深搜(DFS)或者广搜(BFS)来搜。 463. 岛屿的周长 841.钥匙和房间 力扣题目链接 (opens new window) 有 N 个房间,开始时你位于 0…...

把 Taro 项目作为一个完整分包,Taro项目里分包的样式丢失
现象: 当我们把 Taro 项目作为原生微信小程序一个完整分包时,Taro项目里分包的样式丢失,示意图如下: 原因: 在node_modules/tarojs/plugin-indie/dist/index.js文件里,限制了只有pages目录下会被引入app.w…...

腾讯云服务器价格查询系统,2024年1年、3年和5年活动价格表
腾讯云服务器多少钱一年?61元一年起。2024年最新腾讯云服务器优惠价格表,腾讯云轻量2核2G3M服务器61元一年、2核2G4M服务器99元一年可买三年、2核4G5M服务器165元一年、3年756元、轻量4核8M12M服务器646元15个月、4核16G10M配置32元1个月、312元一年、8核…...

第十四届蓝桥杯大赛软件赛省赛Java大学B组
最近正在备考蓝桥杯,报的java b组,顺便更一下蓝桥的 幸运数字 题目 思路:填空题,暴力即可 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不可修改public class Main {static int trans(int x, int y){int …...

Java二阶知识点总结(七)SVN和Git
SVN 1、SVN和Git的区别 SVN是集中式的,也就是会有一个服务器保存所有代码,拉取代码的时候只能从这个服务器上拉取;Git是分布式的,也就是说每个人都保存有所有代码,如果要获取代码,可以从其他人手上获取SV…...

Java后端八股------设计模式
Coffee可以设计成接口。...

DBO优化GRNN回归预测(matlab代码)
DBO-GRNN回归预测matlab代码 蜣螂优化算法(Dung Beetle Optimizer, DBO)是一种新型的群智能优化算法,在2022年底提出,主要是受蜣螂的的滚球、跳舞、觅食、偷窃和繁殖行为的启发。 数据为Excel股票预测数据。 数据集划分为训练集、验证集、测试集,比例…...
Day 31 贪心01
理论基础 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。最好用的策略就是举反例,如果想不到反例,那么就试一试贪心吧。 贪心算法一般分为如下四步: 将问题分解为若干个子问题找出适合的贪心策略求解每一个子问题的最优…...
C++11特性:std::lock_guard是否会引起死锁?
今天在评审代码的时候,因为位于两个不同的线程中(一个是周期性事件线程,一个是触发式事件线程),需要对一个资源类的某些属性进行互斥的访问,因此采用lock_guard互斥量包装器,但是在升级的过程中…...

stm32使用定时器实现PWM与呼吸灯
PWM介绍 STM32F103C8T6 PWM 资源: 高级定时器( TIM1 ): 7 路 通用定时器( TIM2~TIM4 ):各 4 路 例如定时器2 PWM 输出模式: PWM 模式 1 :在 向上计数 时࿰…...

MAC本安装telnet
Linux运维工具-ywtool 目录 1.打开终端1.先安装brew命令2.写入环境变量4.安装telnet 1.打开终端 访达 - 应用程序(左侧) - 实用工具(右侧) - 终端 #注意:登入终端用普通用户,不要用MAC的root用户1.先安装brew命令 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/H…...
[AIGC] 使用Spring Boot进行单元测试:一份指南
在现代软件开发过程中,确认你的应用正确运行是至关重要的一步。Spring Boot提供了一组实用工具和注解来辅助你在测试你的应用时,使得这个过程变得简单。下面就来分享一下如何在Spring Boot中进行单元测试。 文章目录 为什么需要单元测试Spring Boot单元测…...
使用 Go 语言统计 0-200000 的数字中,哪些是素数?
题目 使用 Go 语言统计 0-200000的数字中,哪些是素数? 思路 两种方法: 单循环遍历 1-200000 数字,并判断是否是素数。 使用了 Goroutine 和通道实现并发: 通过创建两个通道 intChan 和 primeChan,以及一…...

Fabric Measurement
Fabric Measurement 布料测量...

wayland(xdg_wm_base) + egl + opengles 使用 Assimp 加载材质文件Mtl 中的纹理图片最简实例(十六)
文章目录 前言一、3d 立方体 model 属性相关文件1. cube.obj2. cube.Mtl3. 纹理图片 cordeBouee4.jpg二、代码实例1. 依赖库和头文件1.1 assimp1.2 stb_image.h2. egl_wayland_obj_cube.cpp3. Matrix.h 和 Matrix.cpp4. xdg-shell-client-protocol.h 和 xdg-shell-protocol.c5.…...

面试常问:为什么 Vite 速度比 Webpack 快?
前言 最近作者在学习 webpack 相关的知识,之前一直对这个问题不是特别了解,甚至讲不出个123....,这个问题在面试中也是常见的,作者在学习的过程当中总结了以下几点,在这里分享给大家看一下,当然最重要的是…...

React腳手架已經創建好了,想使用Vite作為開發依賴
使用Vite作為開發依賴 安裝VITE配置VITE配置文件簡單的VITE配置項更改package.json中的scripts在根目錄中添加index.html現在可以瀏覽你的頁面了 安裝VITE 首先,在現有的React項目中安裝VITE npm install vite --save-dev || yarn add vite --dev配置VITE配置文件 …...
数据结构——双向链表(C语言版)
上一章:数据结构——单向链表(C语言版)-CSDN博客 目录 什么是双向链表? 双向链表的节点结构 双向链表的基本操作 完整的双向链表示例 总结 什么是双向链表? 双向链表是一种常见的数据结构,它由一系列节…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...

wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...