LINUX内核常用加锁
1、mutex互斥锁
互斥锁的实现主要利用到了原子变量可以锁内存总线的机制来对lock变量值进行原子修改,并通过在加锁及释放锁过程中引入内存屏障(加锁引入lfence,释放锁引入sfence),来确保锁临界区资源(Critical Section)能够在不同的CPU之间可见。
如图,CPU_0优先抢占到总线的控制权,并在权限范围内对原子变量执行了atomic_long_try_cmpxchg_acquire操作,将其value值设置成自己的线程ID,并通过lfence来确保线程持锁成功后,可以看到锁临界区资源的最新状态。
CPU_1后抢占到总线的控制权,执行CAS操作时将会出错(由于compare不匹配),此时会将当前线程加入到mutex的等待队列中,然后将CPU切换到其他线程进行处理(引发线程的上下文切换)
持有 mutex锁的线程执行unlock操作时会触发原子变量的atomic_long_try_cmpxchg_release操作(相当于sfence加CAS),并对等待队列中排位靠前的线程进行唤醒。
相关API声明
(1) mutex_init(mutex)
初始化互斥锁,对应的用户态函数为pthread_mutex_init
(2) mutex_lock(mutex)
对目标锁进行抢占,对应的用户态函数为pthread_mutex_lock
(3) mutex_unlock(mutex)
释放锁操作,对应的用户态函数为pthread_mutex_unlock
注意mutex的使用是不可重入的,多次调用mutex_lock会导致线程进入死锁。
2、spinlock自旋锁
自旋锁的实现与mutex有一定相似之处,都是通过对原子变量执行CAS来决定当前线程是否可以进入锁的临界区。不同的是spinlock在无法获取到锁时不会进入等待,而是在while循环中做不断尝试,为此线程的持锁时间不宜过长,否则很容易造成其他线程空耗CPU的行为。
同时,持有锁的线程更不能进入阻塞或者睡眠,为此kernel还会关闭持锁CPU的preemption功能(借助preempt_disable函数)
相关API声明
(1) void spin_lock_init(spinlock_t *lock)
初始化一个splin_lock
(2) void spin_lock(spinlock_t *lock)
抢占目标锁
(3) spin_lock_irqsave | spin_lock_irq
抢占目标锁的同时禁用CPU的中断,防止中断handler抢锁进入死循环
(4) spin_lock_bh
抢占目标锁的同时禁用CPU的软中断(sofirqd),硬中断依然生效
(5) void spin_unlock(spinlock_t *lock)
释放抢占到的锁
(6) spin_unlock_irqrestore | spin_unlock_irq | spin_unlock_bh
释放锁的同时恢复中断
注意自旋锁并不是公平锁,资源竞争压力比较大时,有可能导致某些线程长时间获取不到锁
3、Semaphore信号量
与mutex类似,semaphore也是通过比对一个变量值来决定当前线程是否可以进入锁的临界区,只不过针对变量值的访问,semaphore采用的是spinlock来做同步控制,而mutex则直接基于原子变量。
另外通过semaphore还可允许多个线程同时进入临界区,只有当目标变量值为0时,操作线程才需要进入等待(将CPU调度到其他线程进行处理),直至有其他线程执行up操作将其唤醒。
相关API声明
(1) void sema_init(struct semaphore *sem, int val)
init_MUTEX(name),返回一个semaphore,其val为1
init_MUTEX_LOCKED(name),返回一个semaphore,其val为0
(2) void down(struct semaphore *sem)
信号量的值为0时进入阻塞,否则将信号量的值减1
(3) void up(struct semaphore *sem)
信号量的值加1
(4) void init_rwsem(struct rw_semaphore *sem)
初始化读写信号量
4、seqlocks
不同于mutex互斥锁,基于seqlock的读操作并不需要与写操作形成互斥,读写产生冲突时,只需要在读操作一侧发起重试。
如图,Thread_1对共享资源执行了读操作,Thread_2对共享资源执行了写操作。
当Thread_1执行步骤(1)到步骤(3)之间时,Thread_2执行了write_seqlock,此时Thread_1将会检测到seqcount前后不匹配,然后发起重试对Resource资源进行再次读取。
由于针对seqcount(类似volatile变量)的读取不需要像原子变量一样去锁内存总线,因此其在读链路上的锁同步开销相对较低。
在写链路上Thread_2获取到seqlock写锁之后,会将seqcount值做加1处理,使其变为奇数。此时read_seqbegin将无法再次进入到锁的临界区内,其会在while循环中做不断重试,直至seqcount变为偶数(Thread_2触发了write_sequnlock,将seqcount再次加1),以此来确保目标Resource在更新期间,不会有新的线程对其进行读取,老的线程虽然可能读取到stale数据,但是会在执行read_seqretry时发起重试。
相关API声明
(1) read_seqbegin
对seqcount计数进行读取,当其为奇数时说明有写操作存在,此时会进入while循环来不断的发起重试。
(2) read_seqretry
对seqcount计数再次读取,如果其value发生变化,说明共享资源在读取期间产生了变动,需要触发retry逻辑。
(3) write_seqlock
在spinlock锁内对seqcount进行递增,将其变为奇数,然后触发sfence确保变量值能够在其他CPU可见。
(4) write_sequnlock
在spinlock锁内对seqcount进行再次递增,将其变为偶数,然后释放spinlock锁。
注意seqlock的锁获取逻辑并不会引发线程的上下文切换,这点与spinlock一致。
5、Read-Copy-Update
以游戏服务器在线升级场景为例,可供选择的运维手段有两种
(1) 强制所有玩家下线,服务升级期间拒绝连接
类似对共享资源执行写操作期间,禁止其他线程读取
(2) 启动一个新版本的服务器,同时老的服务器依然运行(但是不在接收新客户端的连接请求)
当老服务器所有玩家都下线之后,在对其做下线处理
毫无疑问第二种方式对玩家更为友好,Read-Copy-Update便是基于该理念进行设计实现。
如图所示,T1时刻CPU_0对指向node_1的资源指针(hlist_node)做了一份本地拷贝(从堆空间拷贝到栈空间)
T2时刻CPU_1将node_1的next指针引向了NEW,并将修改同步到内存(借助rcu_assign_pointer引入的内存屏障)
T3时刻CPU_0对node_1的next指针进行访问,而此时返回的将是node_2而不是NEW
由此可以看出RCU的实现特点
(1) 读操作与写操作并不互斥
CPU_0对node_1进行读取,相当于是对node_1的hlist_node做了一份本地拷贝(通过READ_ONCE确保操作的原子性),从而与Writer端的写入并不冲突
(2) 读操作访问到的数据有可能不是共享资源最新的状态
比如T2时刻CPU_1已经对node_1的next指针做了修改(指向了NEW),但是CPU_0看到的还是node_2
那么应用层如果想要规避这种情况的发生需要如何处理呢?可以结合seqlock一起使用,比如内核针对dcache的一致性处理。
(3) 写操作如果想要对共享资源进行删除,需要等待所有Reader退出临界区
假如T2时刻CPU_1对node_2执行了删除动作,此时并不能马上对node_2的内存资源进行清理,因为后续CPU_0还会对其进行访问。
为此需要等待所有Reader都退出临界区后(类似老服务器所有玩家都下线),删除操作才能真正执行。
相关API声明
(1) rcu_assign_pointer(pointer, value)
RCU要求针对共享资源的访问必须以指针的方式进行(指针可以保证操作原子性,不会造成数据mashup)
rcu_assign_pointer函数会将pointer指向的数据当做volatile变量来处理(具体可参考内核的WRITE_ONCE宏定义),因此对其执行store操作后,其他CPU能够立刻可见。
同时该函数还会在编译阶段引入内存屏障,来防止编译器做上下文之间的指令重排序。
(2) rcu_dereference(pointer)
rcu_dereference同样会将pointer指向的数据内容当作volatile变量来看待,确保了指针数据的读取不是来自于CPU的store buffer和寄存器,同时避免编译器在编译阶段对指令进行重排序。
方法执行后,相当于对pointer所指向的数据内容做了一份本地拷贝(由堆空间拷贝到栈空间)
(3) rcu_read_lock & rcu_read_unlock
rcu_read_lock用于进入读取临界区(期间会调用preempt_disable来禁用CPU的抢占),以确保node_1在读取期间不会被写入端删除。写入端若要删除node_1,需调用synchronize_rcu等待所有reader退出临界区后才能执行(即执行了rcu_read_unlock调用)
(4) synchronize_rcu
等待每个reader退出了锁的临界区,一种实现方式:等待每个CPU产生一次上下文切换
调用rcu_read_lock进入锁临界区后会禁用CPU的抢占,所以CPU一旦产生线程切换,说明之前的线程已经退出了锁临界区(执行了rcu_read_unlock调用)
相关文章:
LINUX内核常用加锁
1、mutex互斥锁 互斥锁的实现主要利用到了原子变量可以锁内存总线的机制来对lock变量值进行原子修改,并通过在加锁及释放锁过程中引入内存屏障(加锁引入lfence,释放锁引入sfence),来确保锁临界区资源(Critical Section)能够在不同的CPU之间可…...
【Select 语法全解密】.NET开源ORM框架 SqlSugar 系列
系列文章目录 🎀🎀🎀 .NET开源 ORM 框架 SqlSugar 系列 🎀🎀🎀 文章目录 系列文章目录前言一、Select 执行位置二、返回一个字段和多个字段三、单表返回DTO四、多表返回DTO4.1 手动DTO4.2 实体自动映射14.…...
STM32之GPIO输出与输出
欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 文章目录 一.GPIO输入1.1GPIP简介1.2GPIO基本结构1.3GPIO位结构1.4GPIO的八种模式1.4.1浮空/上拉/下拉输入1.4.2 模拟输入1.4.3 推挽输出\开漏输出 二.GPIO输入2.1.按键介绍2.2传感器模块介绍2.3按键电路 一.G…...
【数据库】Redis—Java 客户端
一、常见的几种 Java 客户端 Jedis:以 Redis 命令作为方法的名称,便于学习,简单实用,但其实例是线程不安全的,多线程下需要基于连接池来使用。lettce:基于 Netty 实现,支持同步、异步和响应式编…...
《图解机器学习》(杉山将著)第一部分绪论学习笔记
《图解机器学习》(杉山将著)第一部分绪论学习笔记 《图解机器学习》(杉山将著)第一部分绪论学习笔记一、什么是机器学习1.1 学习的种类1.2 机器学习任务的例子1.3 机器学习的方法 二、学习模型2.1 线性模型2.2 核模型2.3 层级模型…...
Deepin和Windows传文件(Xftp,WinSCP)
在Linux系统和Windows系统传输文件,通常通过Windows系统中安装的Xftp和WinSCP访问Linux系统,在访问前需要安装配置SSH-Server 安装SSH-Server 安装SSH-Server sudo apt-get install openssh-server ssh -v 启动SSH服务 sudo systemctl start ssh //也…...
C语言习题2.0
C语言习题1.0 C语言习题-CSDN博客 目录 C语言习题1.0 C语言习题-CSDN博客 找一个数字的连续因子 求N个分数的和 正整数AB 函数 预处理 文件处理 操作符 找一个数字的连续因子 //找连续因子,及其个数 int main() {int a;scanf("%d", &a);int num 0; …...
达梦 本地编码:PG_GBK, 导入文件编码:PG_UTF8错误
问题 达梦 本地编码:PG_GBK, 导入文件编码:PG_UTF8错误 解决 右键管理服务器 查看配置 新建一个数据库实例,配置跟之前的保持一致 新建一个用户,跟以前的用户名一样 在用户上,右键导入,选择dmp的位置 导…...
【Apache Paimon】-- 11 -- Flink 消费 kakfa 写 S3 File
目录 1、项目构建 2、项目新增和修改 2.1 pom.xml 新增依赖 2.2 本地测试或者 flink on k8s 时,新增 S3FileSystemFactory.java 第一步:创建包=org.apache.flink.fs.s3hadoop 第二步:新增 java 类 S3FileSystemFactory 特别注意 (1)本地测试时需要新增以下内容 (…...
使用C语言编写UDP循环接收并打印消息的程序
使用C语言编写UDP循环接收并打印消息的程序 前提条件程序概述伪代码C语言实现编译和运行C改进之自由设定端口注意事项在本文中,我们将展示如何使用C语言编写一个简单的UDP服务器程序,该程序将循环接收来自指定端口的UDP消息,并将接收到的消息打印到控制台。我们将使用POSIX套…...
QT6静态编译并配置及错误解决
使用Github workflow进行编译,无需本地编译。 断断续续半年间,试了很多次静态编译,也尝试过别人编译的静态包,但一直失败。不是无法成功编译,就是编译后无法正常使用,经常报错链接失败。 参考的教程&#…...
Docker部署GitLab服务器
一、GitLab介绍 1.1 GitLab简介 GitLab 是一款基于 Git 的开源代码托管平台,集成了版本控制、代码审查、问题跟踪、持续集成与持续交付(CI/CD)等多种功能,旨在为团队提供一站式的项目管理解决方案。借助 GitLab,开发…...
flink实现复杂kafka数据读取
接上文:一文说清flink从编码到部署上线 环境说明:MySQL:5.7;flink:1.14.0;hadoop:3.0.0;操作系统:CentOS 7.6;JDK:1.8.0_401。 常见的文章中&…...
小雅Alist缓存太多怎么清理?教程来了
声明:不喜欢小白在开头唠嗑的小伙伴可以直接滑动到【 正文开始】处阅读。 前言 前段时间讲到在飞牛OS上部署小雅超集AList,后台看到很多小伙伴都部署了。 飞牛NAS上的小雅根本没有资源?只剩下打赏码?那得按照这个重新配置了&…...
Python字符串及正则表达式(十一):正则表达式、使用re模块实现正则表达式操作
前言:在 Python 编程的广阔天地中,字符串处理无疑是一项基础而关键的技能。正则表达式,作为处理字符串的强大工具,以其灵活的模式匹配能力,在文本搜索、数据清洗、格式验证等领域发挥着不可替代的作用。本系列博客已经…...
前端:金额高精度处理
Decimal 是什么 想必大家在用js 处理 数字的 加减乘除的时候,或许都有遇到过 精度不够 的问题,还有那些经典的面试题 0.20.1 ! 0.3, 至于原因,那就是 js 计算底层用的是 IEEE 754 ,精度上有限制, 那么Deci…...
WPF 依赖属性和附加属性
除了普通的 CLR 属性, WPF 还有一套自己的属性系统。这个系统中的属性称为依赖属性。 1. 依赖属性 为啥叫依赖属性?不叫阿猫阿狗属性? 通常我们定义一个普通 CLR 属性,其实就是获取和设置一个私有字段的值。假设声明了 100 个 …...
git merge 冲突 解决 show case
废话不多说,上 case!!! 1. 更新master分支 package org.example;public class Main {public static void main(String[] args) {System.out.println("--------Git冲突测试代码开始---------");System.out.println(&qu…...
小鹏“飞行汽车”上海首飞,如何保障智能出行的安全性?
近日,小鹏汇天的“陆地航母”飞行汽车在上海陆家嘴成功完成首飞,标志着飞行汽车时代在中国正式拉开序幕。作为一项突破性的科技创新,飞行汽车不仅将重塑我们的出行方式,还将深刻改变城市的交通格局。此次飞行不仅证明了飞行汽车的…...
分析excel硕士序列数据提示词——包含对特征的筛选,非0值的过滤
文章目录 1 分析出发点2 围绕出发点的文件分析3 功能模块计算重心相关性计算教学倾向百分比多列相关性计算结果封装证伪——过滤0后的交叉相关系数封装和总控——批量处理特征筛选——筛选提问倾向最大和最小的前五代码总的清洗1 分析出发点 写一个python代码,遍历"D:\Ba…...
sed | 一些关于 sed 的笔记
sed 总结 sed 语法sed [-hnV] [-e<script>] [-f<script文件>] [文本文件]--- 参数:-e<script> 以选项中指定的script 来处理输入的文本文件-f<script文件> 以选项中指定的script 文件来处理输入的文本文件动作说明:a 新增s 取代d 删除i 插入…...
如何重新设置VSCode的密钥环密码?
故障现象: 忘记了Vscode的这个密码: Enter password to unlock An application wants access to the keyring “Default ke... Password: The unlock password was incorrect Cancel Unlock 解决办法: 1.任意terminal下,输入如下…...
数据结构 (字符串:KMP)
KMP算法: 构造ne数组 和 匹配过程 vector<int> build_next(string s) { vector<int> ne(s.size()); ne[0] -1; for (int i 1, j -1; i < s.size(); i) { while (j ! -1 && s[i] ! s[j 1])j ne[j]; if (s[i…...
剑指offer搜索二维矩阵
题目连接 https://leetcode.cn/problems/search-a-2d-matrix-ii/’ 代码 自己想出来的 解法一 初始化两个指针,i0,j列数-1 若此时matrix[i][j]target 则返回true 若此时matrix[i][j]>target,表明在第j列中不可能存在target,因为列是升序的 若此时ma…...
【LIBS】开源库编译之OSQP
目录 编译环境源码下载本地编译交叉编译 编译环境 【LIBS】开源库编译之编译环境 源码下载 git clone --recursive --branch v0.6.3 https://github.com/osqp/osqp.git libosqp-0.6.3本地编译 cd libosqp-0.6.3cmake -B build_amd64 \-D CMAKE_BUILD_TYPERelease \-D CMAKE…...
【系统移植】制作SD卡启动——将uboot烧写到SD卡
在开发板上启动Linux内核,一般有两种方法,一种是从EMMC启动,还有一种就是从SD卡启动,不断哪种启动方法,当开发板上电之后,首先运行的是uboot。 制作SD卡启动,首先要将uboot烧写到SD卡ÿ…...
.NET重点
B/S C/S什么语言 B/S: 浏览器端:JavaScript,HTML,CSS 服务器端:ASP(.NET)PHP/JSP 优势:维护方便,易于升级和扩展 劣势:服务器负担沉重 C/S java/.NET/…...
米思奇图形化编程之ESP32控制LED灯闪烁方案实现
目录 一、项目概述 二、硬件准备 三、硬件连接 四、软件编程 五、验证效果 六、总结 一、项目概述 本项目使用米思奇图形化编程环境,编写micropython软件代码,实现了控制ESP32开发板上LED灯闪烁效果。该项目可为后续更复杂的物联网项目打下基础。…...
SMMU软件指南SMMU编程之全局错误和最小配置
安全之安全(security)博客目录导读 目录 一、全局错误 二、最小配置 一、全局错误 与编程接口相关的全局错误会报告到适当的 SMMU_(*_)GERROR 寄存器,而不是通过基于内存的事件队列。这些错误通常是严重的,例如导致 SMMU 停止向前推进。例如…...
JavaEE 导读与环境配置
JavaEE 介绍 Java EE(Java Platform Enterprise Edition), Java 平台企业版. 是JavaSE的扩展, ⽤于解决企业级的开发需求, 所以也可以称之为是⼀组⽤于企业开发的Java技术标准. 所以, 学习JavaEE主要是学习Java在企业中如何应⽤ 框架学习 Java EE 课程共涉及4个框架的学习: Spr…...
Cesium 实例化潜入潜出
Cesium 实例化潜入潜出 1、WebGL Instance 的原理 狭义的的WebGL 中说使用 Instance, 一般指使用 glDrawArraysInstanced 用于实例化渲染的函数。它允许在一次绘制调用中渲染多个相同的几何体实例,而无需为每个实例发起单独的绘制调用。 Three.js 就是使用这种方…...
设计模式——适配器模式
1. 定义 适配器模式(Adapter Pattern)属于结构型设计模式,它的主要作用是将一个类的接口转换成客户期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以协同工作。简单来说,就是充当了不同接口之间的 “转…...
Linux安装Docker
如何在虚拟机中安装linux操作系统,参考文章: VMware下Centos7安装步骤-CSDN博客 使用Xshell链接到linux操作系统 执行命令,安装docker的底层工具 sudo yum install -y yum-utils device-mapper-persistent-data lvm2 增加阿里云docker下载仓…...
CH430N 插上电脑无反应
电路图,此处我用的是3.3V供电,现象就是插上USB,电脑没有反应。搜索也搜索不到 抄板请看自己是多少V供电 后来看到也有类似的 换了芯片后就好了。md新板子第一个芯片就是坏的,服了。...
Java实现贪吃蛇游戏
目录 一、项目结构 二、实现步骤 1. 创建 Snake 类 2. 创建 Food 类 3. 创建 GameBoard 类 4. 创建 SnakeGame 类 三、总结 贪吃蛇是一个经典的电子游戏,它的玩法非常简单,但又充满了挑战。玩家通过控制蛇的移动,吃到食物并不断成长&a…...
为SSH2协议服务器的用户设置密钥
目录 私钥的创建1. 在服务器上直接生成2. 如果需要配置免密登录3. 查看生成的密钥 导出私钥至SSH用户获取sudo权限 新的一台服务器类型是SSH2:这表示服务器支持SSH(Secure Shell)协议的第二个版本。SSH是一个网络协议,用于加密方式…...
最新版Chrome浏览器加ActiveX控件之多个VLC控件同时加载
背景 VLC Media Player 是一款可播放大多数格式,而无需安装编解码器包的媒体播放器。可以播放 MPEG-1、MPEG-2、MPEG-4、DivX、DVD/VCD、卫星数字电视频道、地面数字电视频道(digital terrestrial television channels)、在许多作业平台底下透过宽带 IPv4、IPv6 网络…...
sql server 查询对象的修改时间
sql server 不能查询索引的最后修改时间,可以查询表,存储过程,函数,pk 的最后修改时间使用以下语句 select * from sys.all_objects ob order by ob.modify_date desc 但可以参考一下统计信息的最后修改时间,因为索…...
均值聚类算法
K-均值聚类算法是一种常用的无监督学习算法,用于将数据集划分成K个不同的簇。该算法的步骤如下: 1. 选择聚类的个数K。 2. 随机初始化K个聚类中心。 3. 对每个数据点计算其与聚类中心的距离,并将其划分到最近的聚类中心所代表的簇。 4. 对每…...
django中cookie与session的使用
一、cookie cookie由服务器生成 ,存储在浏览器中的键值对数据,具有不安全性,对应敏感数据应该加密储存在服务端每个域名的cookie相互独立浏览器访问域名为A的url地址,会把A域名下的cookie一起传递到服务器cookie可以设置过期时间 django中设…...
Python 协程:并发编程的轻量级利器
一、协程是什么? 协程是一种比线程更加轻量级的存在。它可以在特定的点暂停执行,然后在后续某个时刻恢复执行,并且能够在暂停期间保存其执行状态。与传统的多线程模型不同,协程不需要操作系统进行线程上下文切换的开销,…...
理解JVM
JVM简介 JVM 是 Java Virtual Machine 的简称,意为 Java 虚拟机 虚拟机是指通过软件模拟的具有完整硬件功能的、运行在一个完全隔离的环境中的完整计算机系统 常见的虚拟机: JVM 、 VMwave 、 Virtual Box JVM 和其他两个虚拟机的区别: 1…...
GhostRace: Exploiting and Mitigating Speculative Race Conditions-记录
文章目录 论文背景Spectre-PHT(Transient Execution )Concurrency BugsSRC/SCUAF和实验条件 流程Creating an Unbounded UAF WindowCrafting Speculative Race ConditionsExploiting Speculative Race Conditions poc修复flush and reload 论文 https:/…...
【环境搭建】使用IDEA远程调试Dolphinscheduler
以Dolphinscheduler-3.1.8为例,先把容器起了: $ docker pull apache/dolphinscheduler-standalone-server:3.1.8 $ docker run -d -p 12345:12345 -p 25333:25333 -p 5005:5005 -d apache/dolphinscheduler-standalone-server:3.1.8下载Dolphinschedule…...
强基计划之编程:开启科研精英培养新路径
强基计划之编程:开启科研精英培养新路径 一、强基计划概述 1. 出台背景 在 2003 年,教育部开启高校自主招生改革,于探索综合评价学生、破除招生“唯分数论”等方面收获一定成效。相关调查研究显示,自主招生所录取的学生在入校后…...
奇怪问题| Chrome 访问csdn 创作中心的时候报错: 服务超时,请稍后重试
Chrome 访问csdn 创作中心的时候报错: 服务超时,请稍后重试用无痕浏览器可以正常访问 关闭代理无效清缓存和Cookies无效。考虑无痕浏览器模式下插件不生效,尝试把chrome 插件也禁用,发现有效,是该扩展程序的缘故...
Spring Boot 教程之三十六:实现身份验证
如何在 Spring Boot 中实现简单的身份验证? 在本文中,我们将学习如何使用 Spring设置和配置基本身份验证。身份验证是任何类型的安全性中的主要步骤之一。Spring 提供依赖项,即Spring Security,可帮助在 API 上建立身份验证。有很…...
设计模式中单例模式中懒汉模式的问题
设计模式中单例模式中懒汉模式的问题 今天在项目中遇到了要使用懒汉模式的问题。百度之后,发现还有很多细节是自己之前没有见过的。于是记录一下。下面是在AI助手中的说明。 单例模式的懒汉模式(Lazy Singleton)是在需要时才创建实例&#…...
【唐叔学算法】第18天:解密选择排序的双重魅力-直接选择排序与堆排序的Java实现及性能剖析
引言 在数据排序的世界里,选择排序是一类简单而直观的算法,它通过不断选取未排序部分中的最小(或最大)元素来逐步构建有序序列。今天,我们将深入探讨两种基于选择思想的排序方法——直接选择排序和堆排序,…...
力扣48.旋转图像
文章目录 一、前言二、原地旋转 一、前言 力扣48.旋转图像 这道题要求把给定矩阵旋转90度,并且不允许使用额外矩阵来完成旋转图像。 于是这道题只能使用原地旋转的方法来解决 二、原地旋转 对于一个N3的矩阵来说,只需要两次循环就可以完成了 将A1放到…...