个人笔记---关于详解threadlocal 上下文环境存储的最佳数据类型
个人原因很久没有写代码,对于一些基础的数据类型有一些忘记,可以根据gpt和我当时的问答进行复习
关于拦截器,由于在请求的到达controller处理器之前,拦截器(当然过滤器也可以实现,我感觉都差不多)就把上下文设置在了线程副本中,那么这个请求到处理器的这些代码进行查询出来的上下文也就是这个拦截器设置的上下文咯?这样就百分百线程隔离不会租户混乱哈,然后拦截器中有一个处理请求完毕后删除这个线程副本的方法,来删除这个请求的所属租户是吧,.理论上是线程隔离安全的,但是我害怕多个请求同时经过拦截器导致设置的租户上下文是藏数据,但是我又记得ThreadLocal对于每个访问的线程都是一个副本百分百线程的隔离,所以无需担心,这部分我有一些忘记了,详解一下
你的理解基本是对的!但我们来 详细分析一下 ThreadLocal
的线程隔离特性,确保你的租户上下文不会混乱,并解答你关于并发访问的担忧。
1. ThreadLocal
的线程隔离原理
ThreadLocal
是 每个线程的私有变量存储,它的本质是 每个线程都有自己独立的副本,不会影响其他线程。其核心机制:
ThreadLocal
的值存储在Thread
对象的threadLocals
变量中,而不是ThreadLocal
本身。- 每个线程访问
ThreadLocal
时,都会查找自己线程的threadLocals
,不会干扰其他线程的数据。 - 不同线程访问相同的
ThreadLocal
变量时,各自的数据是独立的,不会互相影响。
所以:
✅ 不会出现多个请求之间的租户数据混乱
✅ 即使多个请求并发执行,ThreadLocal
仍然是线程安全的
2. 你的 拦截器
逻辑分析
由于 拦截器在请求到达
Controller
之前,就已经设置了ThreadLocal
变量,那么后续Service
、Mapper
访问时,就能读取这个ThreadLocal
变量中的租户信息。
流程
-
请求到达拦截器:
- 解析租户 ID(从请求头、JWT、URL 参数等获取)
- 设置
ThreadLocal
保存租户 ID
-
请求进入
Controller -> Service -> Mapper
- 在
Service
或Mapper
查询时,直接从ThreadLocal
获取租户 ID,保证 SQL 查询时是隔离的。
- 在
-
请求处理完成
- 拦截器的
afterCompletion()
方法执行,清理ThreadLocal
变量 - 释放租户数据,防止 线程池复用时数据泄露
- 拦截器的
代码示例
@Component
public class TenantInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String tenantIdStr = request.getHeader("X-Tenant-Id"); // 从请求头获取租户 IDif (tenantIdStr != null) {TenantContext.setCurrentTenant(Long.parseLong(tenantIdStr));}return true; // 继续执行后续请求}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {TenantContext.clear(); // 清除 `ThreadLocal`,防止线程复用导致数据泄露}
}
3. 可能的多线程问题
尽管 ThreadLocal
在单个请求的线程中是安全的,但有 以下两种情况可能导致数据混乱:
(1) 线程池复用问题
Spring MVC 默认使用线程池,请求处理完后线程不会立即销毁,而是会被 回收到线程池。如果不清理 ThreadLocal
,下一个请求可能会 复用上一个请求的租户数据,导致租户数据污染。
✅ 已在 afterCompletion()
里调用 TenantContext.clear()
解决这个问题!
(2) 多线程异步调用问题
如果你的代码在 Controller
或 Service
里使用了 @Async
或者 CompletableFuture
来创建 新的线程,那么这个新线程不会继承 ThreadLocal
变量,导致租户数据丢失。
解决方案
如果你在 @Async
方法里也需要租户信息,你需要 手动传递 tenantId
,或者使用 InheritableThreadLocal
。
✅ 手动传递 tenantId
:
@Async
public void asyncTask(Long tenantId) {TenantContext.setCurrentTenant(tenantId);try {// 执行异步任务} finally {TenantContext.clear();}
}
✅ 使用 InheritableThreadLocal
让子线程继承主线程的租户信息:
public class TenantContext {private static final InheritableThreadLocal<Long> CURRENT_TENANT = new InheritableThreadLocal<>();public static void setCurrentTenant(Long tenantId) {CURRENT_TENANT.set(tenantId);}public static Long getCurrentTenant() {return CURRENT_TENANT.get();}public static void clear() {CURRENT_TENANT.remove();}
}
InheritableThreadLocal
允许子线程 继承 父线程的ThreadLocal
数据,适用于@Async
场景。
4. 总结
✅ ThreadLocal
是线程隔离的,不会导致多个请求的数据混乱
✅ 在 afterCompletion()
里清理 ThreadLocal
,防止线程池复用污染数据
✅ 异步线程不会自动继承 ThreadLocal
,需要手动传递租户 ID 或使用 InheritableThreadLocal
这样,你的 多租户实现就是安全的!🚀
threadlocal 就相当于一个副本地址 当线程访问这个上下文的数据,数据并不在threadlocal这个对象中,而是在访问的线程实列自己身上,那么给我的感觉就像是数据拷贝的地址?
是的,你的理解很接近!但更准确地说,ThreadLocal
并不存储数据本身,而是为每个线程创建一个独立的数据副本,并将这个数据存储在线程的 Thread
实例中。它的本质并不是数据拷贝,而是 线程独享的存储映射。
1. ThreadLocal
的存储结构
(1) ThreadLocal
本身不存储数据
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
这段代码 只是创建了一个 ThreadLocal
变量,并不会真正存储数据。
(2) 每个线程的 Thread
实例内部维护着 ThreadLocal
的数据
每个 Thread
对象内部都有一个 ThreadLocalMap
:
public class Thread {// 线程内部维护一个 ThreadLocalMapThreadLocal.ThreadLocalMap threadLocals = null;
}
当调用 threadLocal.set("data")
时:
ThreadLocal
并不会存数据,它只是 作为 key。- 真实的数据 存储在
ThreadLocalMap
里,并且这个ThreadLocalMap
归属于当前Thread
。
示意图:
线程 A: [ThreadLocalMap] -> { ThreadLocal1 -> "数据A" }
线程 B: [ThreadLocalMap] -> { ThreadLocal1 -> "数据B" }
线程 C: [ThreadLocalMap] -> { ThreadLocal1 -> "数据C" }
每个线程的数据都是 独立存储的,不会互相影响。
2. ThreadLocal
的数据访问机制
当 ThreadLocal
调用 get()
方法时:
- 先获取当前线程
Thread.currentThread()
- 从该线程的
ThreadLocalMap
中取出ThreadLocal
关联的数据
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t); // 获取当前线程的 ThreadLocalMapif (map != null) {ThreadLocalMap.Entry e = map.get(this); // 以当前 ThreadLocal 作为 key 取值if (e != null) {return (T) e.value;}}return null;
}
所以,你说的 “数据并不在 ThreadLocal
对象中,而是在访问的线程实例上” 这个理解是对的!👍
3. 为什么 ThreadLocal
是线程隔离的?
- 每个线程都拥有自己的
ThreadLocalMap
- 数据存储在
ThreadLocalMap
里,而不是ThreadLocal
本身 - 不同线程访问
ThreadLocal
时,只能访问自己线程的ThreadLocalMap
- 不同线程的数据不会互相污染
✅ 因此,ThreadLocal
可以用来存储每个线程的租户 ID,保证租户数据不会串线程!
4. ThreadLocal
只是存了“地址”吗?
可以这么理解,ThreadLocal
本质上是一个 key,而数据是存储在 ThreadLocalMap
里的。但它不是简单的地址拷贝,而是 在每个线程的 ThreadLocalMap
中存储了一个独立的副本。
你可以把它理解成:
每个线程都有一个独立的小型数据仓库,
ThreadLocal
只是仓库的门牌号,而真正的数据在仓库里。
5. 你关心的并发问题
由于每个线程都有自己的 ThreadLocalMap
:
- 线程 A 访问
ThreadLocal
时,只能获取自己ThreadLocalMap
里的数据 - 线程 B 访问
ThreadLocal
时,只能获取自己ThreadLocalMap
里的数据 - 线程 C 访问
ThreadLocal
时,只能获取自己ThreadLocalMap
里的数据
所以:
✅ 线程之间互不影响,线程 A 无法访问线程 B 的数据
✅ 即使多个请求并发执行,每个请求的租户数据都是独立的,不会串数据
6. 需要注意的问题
(1) 线程池问题
如果使用 线程池,线程不会被销毁,而是会被复用。如果不清理 ThreadLocal
,下一个请求可能会复用上一个线程的租户数据,导致数据污染。
✅ 解决方案:在 afterCompletion()
里清理 ThreadLocal
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {TenantContext.clear();
}
(2) 异步线程问题
ThreadLocal
不会自动传播到子线程,如果 @Async
方法需要租户数据,必须手动传递。
✅ 解决方案 1:手动传递租户 ID
@Async
public void asyncTask(Long tenantId) {TenantContext.setCurrentTenant(tenantId);try {// 执行异步任务} finally {TenantContext.clear();}
}
✅ 解决方案 2:使用 InheritableThreadLocal
让子线程继承主线程数据
public class TenantContext {private static final InheritableThreadLocal<Long> CURRENT_TENANT = new InheritableThreadLocal<>();public static void setCurrentTenant(Long tenantId) {CURRENT_TENANT.set(tenantId);}public static Long getCurrentTenant() {return CURRENT_TENANT.get();}public static void clear() {CURRENT_TENANT.remove();}
}
7. 总结
✅ ThreadLocal
不是存数据的,而是一个 key,每个线程的 ThreadLocalMap
里存储数据副本
✅ ThreadLocal
保证了线程隔离,不会导致多个请求的数据串掉
✅ 线程池复用时要 clear()
,否则会数据污染
✅ 异步线程不会继承 ThreadLocal
,需要手动传递或用 InheritableThreadLocal
你现在应该完全理解 ThreadLocal
线程隔离的本质 了吧!🚀
WEB框架的本质
所以threadlocal作为上下文的选择也就体现出来了,对于web框架基本都是对于http请求的链式处理,springboot框架也是,当有一个请求进入处理器controller时候时,ioc会独立一个线程出来进行处理,而这些上文存储的数据也是在这个线程内的,所以这样达到了数据隔离的效果,web框架大多都是这么实现的,比如go的context,和gin这些框架,和python的flask?
完全正确!🎯
在 Spring Boot 这样的 Web 框架里,每个 HTTP 请求都会由一个独立的线程处理(默认是 Tomcat 的线程池提供的 Executor
),而 ThreadLocal
绑定的数据就是 请求范围内独立的上下文,确保数据隔离。
你提到的 Go 的 context
和 Gin、Python 的 Flask 也有类似的机制,虽然它们不使用 ThreadLocal
,但它们的请求上下文处理思路是类似的:
1. Java (Spring Boot) - ThreadLocal
方式
Spring 的 Interceptor
中使用 ThreadLocal
作为请求范围的数据存储:
public class TenantInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {String tenantId = request.getHeader("X-Tenant-ID");TenantContext.setTenant(tenantId); // 存入 ThreadLocalreturn true;}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {TenantContext.clear(); // 清理,防止线程池复用时污染数据}
}
这样,每个请求都有独立的 ThreadLocal
上下文,即使高并发请求,也不会串租户数据。
2. Go (Gin) - context.Context
方式
Go 由于 Goroutine 复用较多,不会使用 ThreadLocal
,而是用 context.Context
显式传递上下文:
func TenantMiddleware() gin.HandlerFunc {return func(c *gin.Context) {tenantID := c.GetHeader("X-Tenant-ID")ctx := context.WithValue(c.Request.Context(), "tenantID", tenantID)c.Request = c.Request.WithContext(ctx)c.Next() // 继续处理}
}
Go 语言不会绑定数据到 Goroutine,而是 显式传递 context.Context
,这样即使 Goroutine 被复用,上下文数据仍然正确。
3. Python (Flask) - g
全局对象
Flask 由于 是单线程处理请求,不需要 ThreadLocal
,而是使用 flask.g
作为请求范围的数据存储:
from flask import Flask, g, requestapp = Flask(__name__)@app.before_request
def before_request():g.tenant_id = request.headers.get("X-Tenant-ID") # 存储租户信息@app.route("/")
def index():return f"Current Tenant: {g.tenant_id}" # 线程安全if __name__ == "__main__":app.run()
Flask 处理请求时,每个请求都有一个独立的 g
,保证不会数据串联。
总结
语言 | Web 框架 | 上下文存储方式 | 线程隔离 |
---|---|---|---|
Java | Spring Boot | ThreadLocal | 线程独立,绑定线程局部变量 |
Go | Gin | context.Context | 显式传递,避免 Goroutine 复用问题 |
Python | Flask | flask.g | 线程局部对象,每个请求独立 |
🚀 不同语言的 Web 框架处理方式不同,但核心目标都是保证请求范围内的数据隔离,防止数据串行和污染!
相关文章:
个人笔记---关于详解threadlocal 上下文环境存储的最佳数据类型
个人原因很久没有写代码,对于一些基础的数据类型有一些忘记,可以根据gpt和我当时的问答进行复习 关于拦截器,由于在请求的到达controller处理器之前,拦截器(当然过滤器也可以实现,我感觉都差不多)就把上下文设置在了线程副本中,那么这个请求到处理器的这些代码进行查询出来的上…...
JVM监控和管理工具
基础故障处理工具 jps jps(JVM Process Status Tool):Java虚拟机进程状态工具 功能 1:列出正在运行的虚拟机进程 2:显示虚拟机执行主类(main()方法所在的类) 3:显示进程ID(PID,Process Identifier) 命令格式 jps […...
【数据结构】树哈希
目录 一、树的同构1. 定义2. 具体理解(1) 结点对应(2) 孩子相同(3) 递归性质 3. 示例 二、树哈希1.定义2.哈希过程(1)叶节点哈希(2)非叶节点哈希(3)组合哈希值 3.性质(1) 唯一性 \re…...
UE5 蓝图学习计划 - Day 12:存储与加载
在游戏开发中,存储(Save)与加载(Load) 系统至关重要,玩家需要能够保存游戏进度、角色状态、道具数据等信息,并在下次启动游戏时恢复它们。UE5 提供了 SaveGame 蓝图类,帮助开发者快速…...
18爬虫:关于playwright相关内容的学习
1.如何在python中安装playwright 打开pycharm,进入终端,输入如下的2个命令行代码即可自动完成playwright的安装 pip install playwright ——》在python中安装playwright第三方模块 playwright install ——》安装playwright所需的工具插件和所支持的…...
图解BWT(Burrows-Wheeler Transform) 算法
Burrows-Wheeler Transform (BWT) 是一种数据转换算法, 主要用于数据压缩领域. 它由 Michael Burrows 和 David Wheeler 在 1994 年提出, 广泛应用于无损数据压缩算法(如 bzip2)中. BWT 的核心思想是通过重新排列输入数据, 使得相同的字符更容易聚集在一起, 从而提高后续压缩算…...
CMake轻松实现把编译生成文件分类输出到指定路径,同时又拷贝一份到别的指定路径(Window/Linux通用)
使用CMake管理的C项目工程你是否有以下需求: 1.项目编译时将生成的文件分类自动输出到指定位置; 2.除了上面输出到指定位置以外,还要拷贝一份到指定位置(包含头文件,配置文件,第三方依赖库文件等…...
AJAX笔记原理篇
黑马程序员视频地址: AJAX-Day03-01.XMLHttpRequest_基本使用https://www.bilibili.com/video/BV1MN411y7pw?vd_source0a2d366696f87e241adc64419bf12cab&spm_id_from333.788.videopod.episodes&p33https://www.bilibili.com/video/BV1MN411y7pw?vd_sour…...
C32.【C++ Cont】静态实现双向链表及STL库的list
目录 1.知识回顾 2.静态实现演示图 3.静态实现代码 1.初始双向链表 2.头插 3.遍历链表 4.查找某个值 4.任意位置之后插入元素 5.任意位置之前插入元素 6.删除任意位置的元素 4.STL库的list 1.知识回顾 96.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删 97.【C…...
【Elasticsearch】terms聚合误差问题
Elasticsearch中的聚合查询在某些情况下确实可能存在误差,尤其是在处理分布式数据和大量唯一值时。这种误差主要来源于以下几个方面: 1.分片数据的局部性 Elasticsearch的索引通常被分成多个分片,每个分片独立地计算聚合结果。由于数据在分…...
2-kafka服务端之延时操作实现原理
文章目录 背景案例延时生产实现原理延时拉取实现原理 总结 背景 上篇我们说到了kafka时间轮是延时操作内部实现的重要数据结构,这篇我们来说下kafka内部的延时操作实现原理。这里我们以延时生产和延时拉取为例说明延时操作的实现原理。 案例 延时生产 我们知道如…...
UE求职Demo开发日志#22 显示人物信息,完善装备的穿脱
1 创建一个人物信息显示的面板,方便测试 简单弄一下: UpdateInfo函数: 就是获取ASC后用属性更新,就不细看了 2 实现思路 在操作目标为装备栏,或者操作起点为装备栏时,交换前先判断能否交换(只…...
【DeepSeek论文精读】6. DeepSeek R1:通过强化学习激发大语言模型的推理能力
欢迎关注[【youcans的AGI学习笔记】](https://blog.csdn.net/youcans/category_12244543.html)原创作品 【DeepSeek论文精读】1. 从 DeepSeek LLM 到 DeepSeek R1 【DeepSeek论文精读】2. DeepSeek LLM:以长期主义扩展开源语言模型 【DeepSeek论文精读】…...
顺丰大数据开发面试题及参考答案
Flink 的提交过程是怎样的? Flink 的提交过程通常包含以下步骤: 代码编写与打包:开发人员首先使用 Flink 提供的 API 编写数据处理逻辑,包括定义数据源、转换操作和数据 sink 等。完成代码编写后,将项目打包成可执行的 JAR 文件,其中包含了所有依赖的库和资源。选择提交方…...
C# 函数多个返回值
有时候需要从C#函数中返回多个返回值,而且返回值的类型又不一样,这个时候又不能用数组或者list。 其实C#函数是支持多个不同类型的返回值的,请参看下面的code. //多返回值函数定义 (string name, int age) GetNameAge(int id) {return (&qu…...
Deepseek 接入Word处理对话框(隐藏密钥)
硅基流动邀请码:1zNe93Cp 邀请链接:网页链接 亲测deepseek接入word,自由调用对话,看截图有兴趣的复用代码(当然也可以自己向deepseek提问,帮助你完成接入,但是提问逻辑不一样给出的答案是千差万…...
RabbitMQ深度探索:简单实现 MQ
基于多线程队列实现 MQ : 实现类: public class ThreadMQ {private static LinkedBlockingDeque<JSONObject> broker new LinkedBlockingDeque<JSONObject>();public static void main(String[] args) {//创建生产者线程Thread producer n…...
Baklib赋能数字内容体验个性化推荐提升用户体验的未来之路
内容概要 随着数字化时代的不断发展,用户对内容消费的需求日益多样化,个性化推荐成为提升用户体验的重要手段。Baklib以其先进的技术手段,在数字内容领域内积极推动个性化推荐的实施,从而满足用户在信息获取和内容消费中的独特需…...
使用 TensorRT 和 Python 实现高性能图像推理服务器
在现代深度学习和计算机视觉应用中,高性能推理是关键。本文将介绍如何使用 TensorRT 和 Python 构建一个高性能的图像推理服务器。该服务器能够接收客户端发送的图像数据,使用 TensorRT 进行推理,并将结果返回给客户端。 1. 概述 1.1 项目目…...
[MySQL#1] database概述 常见的操作指令 MySQL架构 存储引擎
#1024程序员节|征文# 目录 一. 数据库概念 0.连接服务器 1. 什么是数据库 口语中的数据库 为什么数据不直接以文件形式存储,而需要使用数据库呢? 总结 二. ??基础操作 三. 主流数据库 四. 基础知识 服务器,数据库&…...
WebAssembly:前后端开发的未来利器
引言 在互联网的世界里,前端和后端开发一直是两块重要的领域。而 JavaScript 长期以来是前端的霸主,后端则有各种语言诸如 Java、Python、Node.js、Go 等等。然而,近年来一个名为 WebAssembly (Wasm) 的技术正在逐渐改变这一格局。它的高性能…...
Spring Task之Cron表达式
🌟 Spring Task高能预警:你以为的Cron表达式可能都是错的!【附实战避坑指南】 开篇暴击:为什么你的定时任务总在凌晨3点翻车? “明明设置了0 0 2 * * ?,为什么任务每天凌晨3点执行?” —— 来…...
deepseek API 调用-python
【1】创建 API keys 【2】安装openai SDK pip3 install openai 【3】代码: https://download.csdn.net/download/notfindjob/90343352...
数字滤波器的分类
数字滤波器可以根据不同的标准进行分类,以下是几种常见的分类方式: 1. 按实现结构分类 FIR滤波器(有限脉冲响应滤波器) - 特点:系统的脉冲响应在有限时间内衰减到零。 - 优点:线性相位特性(保…...
iOS 老项目适配 #Preview 预览功能
前言 iOS 开发者 最憋屈的就是UI 布局慢,一直以来没有实时预览功能,虽然swiftUI 早就支持了,但是目前主流还是使用UIKit在布局,iOS 17 苹果推出了 #Preview 可以支持UIKit 实时预览,但是仅仅是 iOS 17,老项目怎么办呢?于是就有了这篇 老项目适配 #Preview 预览 的文章,…...
高等代数笔记—域与一元多项式
域与环 数域 F F F:至少包含两个元素且对加减乘除运算封闭的复数集合 F F F,其中作除运算时除数不为0。 封闭:集合 F F F中的两个元素作某一运算的结果仍属于集合 F F F,则称 F F F对该运算封闭。 Q , R , C \mathbb{Q}, \mathbb…...
【C语言设计模式学习笔记1】面向接口编程/简单工厂模式/多态
面向接口编程可以提供更高级的抽象,实现的时候,外部不需要知道内部的具体实现,最简单的是使用简单工厂模式来进行实现,比如一个Sensor具有多种表示形式,这时候可以在给Sensor结构体添加一个enum类型的type,…...
2.Python基础知识:注释、变量以及数据类型、标识符和关键字、输入函数、输出函数、运算符、程序类型转换
1. 注释 注释是用来解释代码,增强代码可读性的部分。在 Python 中,注释分为单行注释和多行注释。 单行注释:以 # 开头,后面的内容都被视为注释。 # 这是一个单行注释 print("Hello, World!") # 输出 "Hello, Wor…...
介绍10个比较优秀好用的Qt相关的开源库
记录下比较好用的一些开源库 1. Qt中的日志库“log4qt” log4qt 是一个基于 Apache Log4j 设计理念的 Qt 日志记录库,它为 Qt 应用程序提供了强大而灵活的日志记录功能。Log4j 是 Java 领域广泛使用的日志框架,log4qt 借鉴了其优秀的设计思想ÿ…...
利用Muduo库实现简单且健壮的Echo服务器
一、muduo网络库主要提供了两个类: TcpServer:用于编写服务器程序 TcpClient:用于编写客户端程序 二、三个重要的链接库: libmuduo_net、libmuduo_base、libpthread 三、muduo库底层就是epoll线程池,其好处是…...
渗透测试之文件包含漏洞 超详细的文件包含漏洞文章
目录 说明 通常分为两种类型: 本地文件包含 典型的攻击方式1: 影响: 典型的攻击方式2: 包含路径解释: 日志包含漏洞: 操作原理 包含漏洞读取文件 文件包含漏洞远程代码执行漏洞: 远程文件包含…...
高性能 :DeepSeek-V3 inference 推理时反量化实现 fp8_cast_bf16
FP8 (8 bits) & FP16 (16 bits) FP8 和 BF16 都是浮点数格式(floating-point formats),float通过科学计数法表示数据,float [符号位指数位系数位] FP8 (8 bits):SEEEMMMMFP16 (16 bits):SEEEEEMMMMM…...
kakailio官网推荐的安装流程ubuntu 22.04
https://kamailio.org/docs/tutorials/6.0.x/kamailio-install-guide-git/ # 非必须项 wget -O- https://deb.kamailio.org/kamailiodebkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/kamailio.gpg在/etc/apt/sources.list文件追加以下内容 deb [signed-by/usr/sh…...
能否通过蓝牙建立TCP/IP连接来传输数据
前言: 最近在做一个项目时,产生了一个疑问:能否通过蓝牙建立TCP/IP连接来传输数据 查阅了一些文章,可以得出结论:不行 下面是我截取的两篇个人认可的文章的回答: 文章一: 蓝牙是一种短距离无…...
git基础使用--1--版本控制的基本概念
文章目录 git基础使用--1--版本控制的基本概念1.版本控制的需求背景,即为啥需要版本控制2. 集中式版本控制SVN3. 分布式版本控制 Git4. SVN和Git的比较 git基础使用–1–版本控制的基本概念 1.版本控制的需求背景,即为啥需要版本控制 先说啥叫版本&…...
高端入门:Ollama 本地高效部署DeepSeek模型深度搜索解决方案
目录 一、Ollama 介绍 二、Ollama下载 2.1 官网下载 2.2 GitHub下载 三、模型库 四、Ollmal 使用 4.1 模型运行(下载) 4.2 模型提问 五、Ollama 常用命令 相关推荐 一、Ollama 介绍 Ollama是一个专为在本地机器上便捷部署和运行大型语言模型&…...
高级java每日一道面试题-2025年01月30日-框架篇[SpringBoot篇]-如何理解 Spring Boot 配置加载顺序 ?
如果有遗漏,评论区告诉我进行补充 面试官: 如何理解 Spring Boot 配置加载顺序 ? 我回答: 在 Java 高级面试中讨论 Spring Boot 配置加载顺序时,理解其机制对于有效管理和调试应用程序配置至关重要。Spring Boot 通过一系列预定义的规则来确定如何加载和覆盖配置…...
代码随想录day06
242.有效的字母异位词 刚学哈希表想着使用unordered_set来实现,结果无法通过,原因是对字母异位词理解有问题,字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语,并使用所有原字母一次。对字母出现的次数有要求&am…...
C#常用744单词
1.visual 可见的 2.studio 工作室 3.dot 点 4.net 网 5.harp 尖端的,锋利的。 6.amework 骨架,构架,框架 7.beta 测试版,试用版 8.XML(全称:eXtensible Markup Language)…...
14.PPT:中国注册税务师协会宣传【26】
目录 NO12 NO3/4/5 NO678 【文本框水平/垂直居中】【文本框内容水平/垂直居中】 NO12 坑:注意❗Word文档的PPt素材.docx的标题大纲是混乱的,虽然他设置了,所以我们需要重新设置 设计→主题视图→幻灯片母版→删除版式插入logo NO3/4…...
Python大数据可视化:基于Python的王者荣耀战队的数据分析系统设计与实现_flask+hadoop+spider
开发语言:Python框架:flaskPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 管理员登录 管理员功能界面 比赛信息管理 看板展示 系统管理 摘要 本文使用Python与…...
简单3步部署本地国产大模型DeepSeek大模型
简单3步部署本地国产大模型DeepSeek大模型 DeepSeek是最近非常火的开源大模型,国产大模型 DeepSeek 凭借其优异的性能和对硬件资源的友好性,受到了众多开发者的关注。 无奈,在使用时候deepseek总是提示服务器繁忙,请稍后再试。 …...
Redis常见数据类型与编码方式
⭐️前言⭐️ 本小节围绕Redis中常见的数据类型与编码方式展开。 🍉欢迎点赞 👍 收藏 ⭐留言评论 🍉博主将持续更新学习记录收获,友友们有任何问题可以在评论区留言 🍉博客中涉及源码及博主日常练习代码均已上传GitHu…...
利用matlab寻找矩阵中最大值及其位置
目录 一、问题描述1.1 max函数用法1.2 MATLAB中 : : :的作用1.3 ind2sub函数用法 二、实现方法2.1 方法一:max和find2.2 方法二:max和ind2sub2.3 方法对比 三、参考文献 一、问题描述 matlab中求最大值可使用函数max,对于一维向量࿰…...
解锁云电脑爽玩TGA游戏,ToDesk、海马云等多款云电脑游戏横测
作为一名游戏爱好者,我深入研究了云电脑技术在游戏娱乐中的应用。通过对比传统游戏机与云电脑的成本效益,我发现云电脑以其低成本和灵活性脱颖而出。我以自身为例,分析了云电脑如何满足对游戏体验的高要求。在测评中,我选择了ToDe…...
蓝桥杯思维训练(五)
文章目录 子集II1191.K次串联后最大子数组之和 子集II 子集II 思路分析: 求解子集的问题的关键就是,通过递归与回溯,我们就是得确定以某个元素开始的子集,对于这个题目来说,比较麻烦的一点就是,存在重复的…...
kaggle视频行为分析1st and Future - Player Contact Detection
这次比赛的目标是检测美式橄榄球NFL比赛中球员经历的外部接触。您将使用视频和球员追踪数据来识别发生接触的时刻,以帮助提高球员的安全。两种接触,一种是人与人的,另一种是人与地面,不包括脚底和地面的,跟我之前做的这…...
2025 CCF BDCI|“基于TPU平台的OCR模型性能优化”一等奖作品
2024年12月,中国计算机学会在海南博鳌成功举办了第十二届CCF大数据与计算智能大赛(简称2024 CCF BDCI)。本届比赛的算能赛道吸引了1748名选手报名,经过激烈角逐,北京航空航天大学的“常务副SOTA”团队脱颖而出…...
结合深度学习、自然语言处理(NLP)与多准则决策的三阶段技术框架,旨在实现从消费者情感分析到个性化决策
针对电商个性化推荐场景的集成机器学习和稳健优化三阶段方案。 第一阶段:在线评论数据处理,利用深度学习和自然语言处理技术进行特征挖掘,进而进行消费者情感分析,得到消费者偏好 在第一阶段,我们主要关注如何通过深度学习和自然语…...
Linux系统安装Nginx详解(适用于CentOS 7)
目录 1. 更新系统包 2. 安装EPEL仓库 3. 安装Nginx 4. 启动Nginx服务 5. 设置Nginx开机自启 6. 检查Nginx状态 7. 配置防火墙 8. 访问Nginx默认页面 9. 配置Nginx(可选) 10. 重启Nginx 解决步骤 1. 检查系统版本 2. 移除错误的 Nginx 仓库 …...