当前位置: 首页 > news >正文

多线程-线程本地变量ThreadLocal

简介

ThreadLocal是线程本地变量,用于存储独属于线程的变量,这些变量可以在同一个线程内跨方法、跨类传递。每一个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal实例

常用操作:ThreadLocal有set、get、remove三个动作,分别对应存储、获取、清除

ThreadLocal的实际应用:

  • 案例1:jdbc中使用ThreadLocal来存储数据库连接,从而实现事务控制的功能。ThreadLocal可以保证同一个线程内获取到的数据库连接是同一个,用户可以在这个连接下开启事务、执行sql、提交事务。
  • 案例2:在某些业务系统中,会使用ThreadLocal来存储发起当前请求的用户的信息,当请求来临时,把用户信息放到ThreadLocal中,处理完请求后,清理ThreadLocal中的用户信息,这样,在处理请求时,在业务代码中就可以通过ThreadLocal来获取用户信息。

ThreadLocal的运行机制:

  • 向ThreadLocal中设置元素时,ThreadLocal会获取当前线程对象中的ThreadLocalMap实例,
    • 如果可以获取到,ThreadLocal会把自己作为键,set方法的参数作为值,存储到ThreadLocalMap中,
    • 如果获取不到,就创建一个ThreadLocalMap

使用案例

案例1:基本使用

基本使用,这里演示了ThreadLocal的set、get、remove

private static final ThreadLocal<String> LOCAL = new ThreadLocal<>();public static void main(String[] args) {// 向threadLocal中存入变量LOCAL.set("aaa");// 获取变量System.out.println("local.get() = " + LOCAL.get()); // aaa// 移除变量LOCAL.remove();System.out.println("local.get() = " + LOCAL.get()); // null
}

案例2:多个线程操作同一个ThreadLocal

多个线程操作同一个ThreadLocal实例,同时向里面设置元素、获取元素,验证会不会出现线程安全问题?

private static final ThreadLocal<Object> LOCAL_VAR = new ThreadLocal<>();public static void main(String[] args) {// 线程1new Thread(() -> {LOCAL_VAR.set(Thread.currentThread().getName());Utils.println(LOCAL_VAR.get());  // t1LOCAL_VAR.remove();Utils.println("after remove : " + LOCAL_VAR.get()); // null},"t1").start();// 线程2new Thread(() -> {LOCAL_VAR.set(Thread.currentThread().getName());Utils.println(LOCAL_VAR.get());  // t2LOCAL_VAR.remove();Utils.println("after remove : " + LOCAL_VAR.get()); // null},"t2").start();
}

总结:不会出现线程安全问题。原因随后讲

案例3:一个线程操作多个ThreadLocal

private static final ThreadLocal<Object> LOCAL_VAR = new ThreadLocal<>();
private static final ThreadLocal<Object> LOCAL_VAR_2 = new ThreadLocal<>();public static void main(String[] args) {new Thread(() -> {// 设置并打印本地变量LOCAL_VAR.set("aa");LOCAL_VAR_2.set("bb");Utils.println(LOCAL_VAR.get()); // aaUtils.println(LOCAL_VAR_2.get()); // bb// 清除本地内存中的本地变量LOCAL_VAR.remove();LOCAL_VAR_2.remove();},"t1").start();
}

总结:如果线程需要n个本地局部变量,那么它就需要使用n个ThreadLocal实例,一个ThreadLocal实例对应当前线程中的一个本地变量

案例4:使用ThreadLocal,实现线程间的数据隔离

java1.1提供的日期类是线程不安全的,这里使用ThreadLocal来解决线程安全的问题

public static void main(String[] args) {ThreadLocal<SimpleDateFormat> dateFormatThreadLocal = new ThreadLocal<>();for(int i = 0; i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {// 创建一个格式化日期的实例,然后存放到ThreadLocal中dateFormatThreadLocal.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));Date date = null;try {date = dateFormatThreadLocal.get().parse("2021-08-15 12:08:09");} catch (ParseException e) {e.printStackTrace();}Utils.println("date = " + date);dateFormatThreadLocal.remove();}}).start();}
}

总结:SimpleDateFormat本身是线程不安全的,在这个案例中,每个线程都会创建一个SimpleDateFormat实例,然后存入到ThreadLocal中,使用时再从ThreadLocal中取出,避免多个线程复用同一个SimpleDateFormat实例,从而实现线程安全。在实际使用中,这也是一种解决问题的方式。但是,ThreadLocal最常见的操作还是用于在同一个线程内跨方法、跨类传递变量,通常不会考虑用ThreadLocal来实现线程安全,因为这样做消耗也会成倍增加,例如在本案例中,有几个线程,就需要几个SimpleDateFormat实例。常见的策略是,考虑把多线程共享的实例做成无状态的,只负责计算,不存储数据,如果确实需要访问共享资源,可以使用锁。

源码分析

ThreadLocal的类结构

public class ThreadLocal<T> {  // 泛型T,是ThreadLocal中存储的元素的数据类型// 静态内部类ThreadLocalMapstatic class ThreadLocalMap {// 静态内部类中还有一个静态内部类 Entry,注意,这里Entry继承了WeakReference,它代表弱引用static class Entry extends WeakReference<ThreadLocal<?>> {// 这里的value就是ThreadLocal调用set时存入的值Object value;Entry(ThreadLocal<?> k, Object v) {super(k);  // key是弱引用value = v;}}// 存储变量的数据结构private Entry[] table;private int size = 0;private int threshold;}
}// Thread类中持有ThreadLocalMap的引用,这就是线程局部变量存放的地方
public class Thread implements Runnable {ThreadLocal.ThreadLocalMap threadLocals = null;
}

总结:这里最关键的是ThreadLocalMap,它被声明在ThreadLocal中,同时,Thread持有ThreadLocalMap的实例,这个实例中存放的就是线程本地变量。而且要注意,ThreadLocalMap中的Entry,它用于包装键值对,键是弱引用,随后会学习到。

set方法

用户调用set方法,向当前线程存入一个局部变量

// ThreadLocal中的set方法
public void set(T value) {// 获取当前线程对象Thread t = Thread.currentThread();// 获取线程对象内ThreadLocalMap类型的成员变量ThreadLocalMap map = getMap(t);// 如果map不等于null,以当前threadLocal对象作为键,把用户指定的值设置到map中if (map != null)map.set(this, value);else// 创建map对象,设置键值对createMap(t, value);
}

最终会把变量设置到ThreadLocalMap中,注意,在这个map中,key是ThreadLocal,值是set方法的参数

get方法

获取ThreadLocal在当前线程实例中对应的值

public T get() {// 获取当前线程对象Thread t = Thread.currentThread();// 获取线程对象内ThreadLocalMap类型的成员变量ThreadLocalMap map = getMap(t);// 如果map不等于nullif (map != null) {// 以当前threadLocal对象作为键,获取键值对ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {// 获取键值对中的值@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}// 如果map等于null,这里是将键置为当前对象,值置为null,然后返回null值return setInitialValue();
}

同样,这里是从Thread实例中获取ThreadLocalMap的实例,然后使用ThreadLocal作为key,从ThreadLocalMap中获取value,remove方法也类似

ThreadLocalMap

ThreadLocalMap,顾名思义,它是一个map,存储键值对,在之前学习set、get方法时,发现所有的变量最终都会存储到其中,并且key是ThreadLoal。在这里深入了解ThreadLocalMap是如何存储数据的。

ThreadLocalMap类似于HashMap,底层是数组,根据key的哈希值,计算下标,然后把元素存放到下标处,和HashMap不同的在于,如果有冲突,它没有采用链地址法来处理冲突,而是把元素直接存放到 下标 + 1 的位置,如果 下标 + 1 = 数组长度,直接把元素存入第0位,然后一直循环,直到找到空位。

ThreadLocalMap的成员变量:

static class ThreadLocalMap {private Entry[] table;  // 存储元素的底层数组private int size = 0;   // 元素个数private static final int INITIAL_CAPACITY = 16;  // 数组的初始容量private int threshold;  // 阈值,决定何时扩容// 构造方法,构造方法的参数是第一个键值对,会把它们存入数组中。ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table = new Entry[INITIAL_CAPACITY];// 计算下标int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);}}

存放键值对的方法:set方法(这里是ThreadLocalMap中的set方法,不是ThreadLocal中的)

// 参数是键值对,注意,键是ThreadLocal
private void set(ThreadLocal<?> key, Object value) {Entry[] tab = table;int len = tab.length;// 计算下标,哈希值和 数组长度 - 1 按位与,了解HashMap的这招都不陌生,// 数组长度要求必须是2的次方,按位与的结果是0到数组长度减1int i = key.threadLocalHashCode & (len-1);// for循环,如果进入循环,表示下标处已经有值,就需要处理哈希冲突for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();// 如果新增的key和原先的key一样,更新valueif (k == key) {e.value = value;return;}// 如果key是null,清理value。这里证明发生了内存泄漏,// 因为key都没有了,但是值还在,所以需要清理value,随后详细讲解。if (k == null) {replaceStaleEntry(key, value, i);return;}}// 循环结束,证明找到了可以存放元素位置,存放元素tab[i] = new Entry(key, value);int sz = ++size;// 如果元素个数大于阈值,扩容if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
}

根据键获取值的方法:getEntry方法

private Entry getEntry(ThreadLocal<?> key) {// 计算下标,获取元素int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];if (e != null && e.get() == key)// 如果键值对中键是匹配的,返回键值对return e;else// 如果没有找到元素,可能发生了哈希冲突,需要继续寻找return getEntryAfterMiss(key, i, e);
}// TgetEntryAfterMiss方法,处理哈希冲突
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {Entry[] tab = table;int len = tab.length;while (e != null) {ThreadLocal<?> k = e.get();if (k == key)return e;// 如果键等于null,将value置为null,同样涉及到内存泄漏if (k == null)expungeStaleEntry(i);else// 下一个下标i = nextIndex(i, len);e = tab[i];}return null;
}

总结:这一节描述了ThreadLocalMap是如何存储和获取元素的,和普通的map基本类似,只不过它使用了再寻址法来处理哈希冲突。

ThreadLocalMap的工作机制:在学习了一部分ThreadLocal的源码之后,这里用文字和图片总结一下ThreadLocal的工作机制

工作机制:

  • ThreadLocal内部定义了ThreadLocalMap
  • Thread类持有ThreadLocalMap的实例
  • ThreadLocalMap中维护了一个数组,数组中的每一个元素都是一个键值对,键是当前ThreadLocal实例,值是用户设置的值。
  • 同一个线程操作的多个ThreadLocal实例,都存储在一个ThreadLocalMap中
  • 多个线程操作同一个ThreadLocal实例,每个线程都有自己的ThreadLocalMap,key是同一个,但map有多个,key对应的值分别存储在不同的map中。

时序图:

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159在这里插入图片描述
png?origin_url=.%2Fimage%2F3.%E5%A4%9A%E7%BA%BF%E7%A8%8B-%E7%BA%BF%E7%A8%8B%E5%B1%80%E9%83%A8%E5%8F%98%E9%87%8F%2Fimage-20250227173936522.png&pos_id=img-NJ9FX13n-1741182359260)

ThreadLocal的内存泄漏

ThreadLocal内存泄露指的是,虽然ThreadLocalMap中的键被回收了,但是值还在

发生内存泄漏的原因:

  1. 用户在自己编写的代码中声明的ThreadLocal对象,本身是一个强引用,这个ThreadLocal对象同时会作为ThreadLocalMap中的键,这个键是一个弱引用。
  2. 只要用户代码中ThreadLocal类型的对象没被回收,它的值不等于null,那ThreadLocalMap中的key就不会在GC时被回收。
  3. 如果用户代码中ThreadLocal类型的对象被置为null,ThreadLocalMap中的key会在GC时被回收,如果此前没有移除value,那么这个value就会无法被获取到
  4. ThreadLocalMap是依附在Thread上的,只要Thread销毁,那ThreadLocalMap也会销毁,但是如果线程一直存在,value一直无法回收,就会造成内存泄漏

为什么要将ThreadLocalMap的key设置为弱引用呢?外界是通过ThreadLocal来对ThreadLocalMap进行操作的,假设外界使用ThreadLocal的对象被置null了,那ThreadLocalMap的强引用指向ThreadLocal也毫无意义,弱引用反而可以预防大多数内存泄漏的情况,毕竟被回收后,下一次调用set/get/remove时ThreadLocal内部会清除掉value

ThreadLocal针对内存泄漏做的保护措施:如果在操作ThreadLocal时,发现key为null,会将value清除掉,同时会遍历map,寻找是否还有这样的值

存在长期性内存泄露需要满足条件:ThreadLocal被回收、线程被复用、线程复用后不再调用ThreadLocal的set/get/remove方法

如何避免:一个set对应一个remove,一定要确保元素在不用之后被移除。

相关文章:

多线程-线程本地变量ThreadLocal

简介 ThreadLocal是线程本地变量&#xff0c;用于存储独属于线程的变量&#xff0c;这些变量可以在同一个线程内跨方法、跨类传递。每一个ThreadLocal对象&#xff0c;只能为当前线程关联一个数据&#xff0c;如果要为当前线程关联多个数据&#xff0c;就需要使用多个ThreadLo…...

MuBlE:为机器人操作任务规划提供了逼真的视觉观察和精确的物理建模

2025-03-05&#xff0c;由华为诺亚方舟实验室、捷克技术大学和帝国理工学院联合开发的MuBlE&#xff08;MuJoCo and Blender simulation Environment&#xff09;模拟环境和基准测试。通过结合MuJoCo物理引擎和Blender高质量渲染&#xff0c;为机器人操作任务规划提供了逼真的视…...

计算机网络笔记(一)——1.1计算机网络在信息时代中的作用

21世纪的一些重要特征是数字化、网络化和信息化&#xff0c;它是一个以网络为核心的信息时代。要实现信息化就必须依靠完善的网络&#xff0c;因为网络可以迅速地传递信息。网络现在已经成为信息社会的命脉和发展知识经济的重要基础。 有三大类网络大家应该很熟悉&#xff0c;即…...

第十五届蓝桥杯省赛电子类单片机学习过程记录(客观题)

客观试题: 01.典型的BUCK电源电路包含哪些关键器件(ABCD) A. 电容 B. 二极管 C. 电感 D. MOSFET 解析: 典型的 BUCK 电源电路是一种降压型的直流-直流转换电路,它包含以下关键器件: A.电容:电容在电路中起到滤波的作用。输入电容用于平滑输入电压的波动,减少电源噪声对…...

计算机组成与体系结构-存储系统

主存编址 存储单元&#xff1a;最小存储单元&#xff0c;一般为4bit。每个存储单元有自己的二进制编号 存储器&#xff1a;多个存储单元排布而成。常见的有8*4存储器&#xff08;8个4bit的存储单元&#xff09; 编址内容&#xff1a; 按字编址&#xff1a;存储体的最小存储单…...

better-sqlite3之exec方法

在 better-sqlite3 中&#xff0c;.exec() 方法用于执行包含多个 SQL 语句的字符串。与预编译语句相比&#xff0c;这种方法性能较差且安全性较低&#xff0c;但有时它是必要的&#xff0c;特别是当你需要从外部文件&#xff08;如 SQL 脚本&#xff09;中执行多个 SQL 语句时。…...

WinUI 3 支持的三种窗口 及 受限的窗口透明

我的目标 希望能够熟悉 WinUI 3 窗口的基本使用方式&#xff0c;了解可能出现的问题 。 WinUI 3 支持三种窗口模式&#xff0c;分别为&#xff1a;常规窗口模式、画中画模式、全屏模式。 窗口模式&#xff1a;常规 即我们最常见的普通窗口。 支持&#xff1a;显示最大化按钮…...

【运维笔记】Navicat中删除mongo 某个时间之前的数据

【运维笔记】Navicat中删除mongo 某个时间之前的数据 一、场景与需求1.1、场景1.2、需求 二、解决方案三、实战3.1、【Navicat】使用sql语句 &#xff08;推荐&#xff09;Step 1&#xff1a;使用查询窗口 - 查询Step 2&#xff1a;确认第一步的数据是否是需要删除的数据Step 3…...

java2025年常见设计模式面试题

1. 请解释建造者模式&#xff08;Builder Pattern&#xff09;及其应用场景。 答案&#xff1a; 建造者模式用于创建一个复杂的对象&#xff0c;同时允许用户只通过指定复杂对象的类型和内容就能构建它们&#xff0c;隐藏了复杂的构建逻辑。 示例&#xff1a; public class C…...

Docker部署Ragflow(完美解决502 bad gateway)

Docker快速启动Ragflow:Dev 系统准备 ubuntu server 24.04 CPU ≥ 4 cores (x86);RAM ≥ 16 GB;Disk ≥ 100 GB; 更新系统 sudo apt update 下载源码 git clone https://github.com/infiniflow/ragflow.git cd ragflow/docker # 切换稳定版本分支 git checkout -f v0.17.…...

算法中的背包问题详解:部分背包与0-1背包

1. 背包问题概述 背包问题是组合优化中的经典问题&#xff0c;其核心目标是&#xff1a;在给定容量的背包中装入一组物品&#xff0c;使得物品的总价值最大化。根据物品是否可分割或重复选择&#xff0c;背包问题分为多个变种&#xff0c;其中最常见的两种是&#xff1a; 部分…...

Stream特性(踩坑):惰性执行、不修改原始数据源

在日常开发中&#xff0c;Stream API 提供了一种高效且易于使用的工具集来处理集合数据。 本文主要讲解 Stream 的两个特性&#xff1a;惰性执行&#xff0c;不修改原始数据源。 为什么说这两个、而不讲下其他的特性呢&#xff1f;主要是因为在开发中如果忽略这两个特性的话&…...

Varlens(手机上的单反)Ver.1.9.3 高级版.apk

Varlens 是一款专业级手机摄影软件&#xff0c;旨在通过丰富的功能和高自由度参数调节&#xff0c;让手机拍摄效果媲美微单相机。以下是核心功能总结&#xff1a; 一、核心功能 专业拍摄模式 支持手动/自动/程序模式&#xff0c;可调节ISO、快门速度、EV、白平衡等参数27 提供…...

【无监督学习】层次聚类步骤及matlab实现

层次聚类 &#xff08;四&#xff09;层次聚类1.算法步骤2.MATLAB 实现参考资料 &#xff08;四&#xff09;层次聚类 层次聚类是一种通过逐层合并或分裂数据点构建树状结构&#xff08;树状图&#xff0c;Dendrogram&#xff09;的聚类方法。它分为两种类型&#xff1a; 凝聚…...

uploadlabs通关思路

目录 靶场准备 复现 pass-01 代码审计 执行逻辑 文件上传 方法一&#xff1a;直接修改或删除js脚本 方法二&#xff1a;修改文件后缀 pass-02 代码审计 文件上传 1. 思路 2. 实操 pass-03 代码审计 过程&#xff1a; 文件上传 pass-04 代码审计 文件上传 p…...

doris:Elasticsearch

Elasticsearch Catalog 除了支持自动映射 ES 元数据外&#xff0c;也可以利用 Doris 的分布式查询规划能力和 ES(Elasticsearch) 的全文检索能力相结合&#xff0c;提供更完善的 OLAP 分析场景解决方案&#xff1a; ES 中的多 index 分布式 Join 查询。 Doris 和 ES 中的表联合…...

JetBrains学生申请

目录 JetBrains学生免费授权申请 IDEA安装与使用 第一个JAVA代码 1.利用txt文件和cmd命令运行 2.使用IDEA新建项目 JetBrains学生免费授权申请 本教程采用学生校园邮箱申请&#xff0c;所以要先去自己的学校申请校园邮箱。 进入JetBrains官网 点击立即申请&#xff0c;然…...

PDFMathTranslate安装使用

PDF全文翻译&#xff01;&#xff01;&#xff01;&#xff01; PDFMathTranslate安装使用 它是个啥 PDFMathTranslate 可能是一个用于 PDF 文件的数学公式翻译 工具。它可能包含以下功能&#xff1a; 提取 PDF 内的数学公式 将数学公式转换成 LaTeX 代码 翻译数学公式的内…...

清华北大推出的 DeepSeek 教程(附 PDF 下载链接)

清华和北大分别都有关于DeepSeek的分享文档&#xff0c;内容非常全面&#xff0c;从原理和具体的应用&#xff0c;大家可以认真看看。 北大 DeepSeek 系列 1&#xff1a;提示词工程和落地场景.pdf  北大 DeepSeek 系列 2&#xff1a;DeepSeek 与 AIGC 应用.pdf  清华 Deep…...

2025-03-09 学习记录--C/C++-PTA 练习11-4 字符定位(最后一次找到的字符)

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h> char *match(char *s, char ch); int main(void …...

C语言数据结构之顺序表

目录 1.线性表 2.顺序表 2.1.静态顺序表 2.2.动态顺序表 2.2.1.初始化 2.2.2.清空顺序表 2.2.3.扩容&#xff0b;尾插 2.2.4.尾出函数 2.2.5.头插函数 2.2.6.头出函数 2.2.7.在中间位置插入 2.2.8.删除中间位置数据 2.2.9.查找函数 2.2.10.总结 3.OJ例题 3.1.合…...

【Git】合并冲突

合并冲突 可是&#xff0c;在实际分支合并的时候&#xff0c;并不是想合并就能合并成功的&#xff0c;有时候可能会遇到代码冲突的问题。 为了演示这问题&#xff0c;创建一个新的分支 dev1 &#xff0c;并切换至目标分支&#xff0c;我们可以使用 git checkout -b dev1 一步…...

【每日学点HarmonyOS Next知识】Web跨域资源、Web长按菜单、Web拦截请求、禁止录屏、Base64图片宽高

1、HarmonyOS Web组件本地资源跨域问题&#xff1f; 关于资源跨域问题的解决&#xff0c;可以参考以下官网文档&#xff1a;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/web-cross-origin-V5 方法一 为了使Web组件能够成功访问跨域资源&#xff0c;开…...

高效数据分析实战指南:Python零基础入门

高效数据分析实战指南 —— 以Python为基石&#xff0c;构建您的数据分析核心竞争力 大家好&#xff0c;我是kakaZhui&#xff0c;从事数据、人工智能算法多年&#xff0c;精通Python数据分析、挖掘以及各种深度学习算法。一直以来&#xff0c;我都发现身边有很多在传统行业从…...

【语料数据爬虫】Python爬虫|批量采集征集意见稿数据(1)

前言 本文是该专栏的第5篇,后面会持续分享Python爬虫采集各种语料数据的的干货知识,值得关注。 在本文中,笔者将主要来介绍基于Python,来实现批量采集“征集意见稿”数据。同时,本文也是采集“征集意见稿”数据系列的第1篇。 采集相关数据的具体细节部分以及详细思路逻辑…...

电力场景绝缘子缺陷分割数据集labelme格式1585张4类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;1585 标注数量(json文件个数)&#xff1a;1585 标注类别数&#xff1a;4 标注类别名称:["broken part","broken insulat…...

《C++ 构造、拷贝构造与析构函数:对象的诞生、克隆与消逝之旅》

类的6个默认成员函数 构造函数 是对一个对象实例化时的初始化 例如在C语言中写的堆的时候要初始化StackInit&#xff0c;而c祖师爷写的构造函数本质上就是自动调用初始化。 构造函数默认构造函数自己写的&#xff08;符合规定的显示表达式&#xff09; 注&#xff1a;一般情况下…...

uniapp uniCloud引发的血案(switchTab: Missing required args: “url“)!!!!!!!!!!

此文章懒得排版了&#xff0c;为了找出这个bug, 星期六的晚上我从9点查到0点多&#xff0c;此时我心中一万个草泥马在崩腾&#xff0c;超级想骂人&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; uniCloud 不想…...

【论文阅读】VAD: Vectorized Scene Representation for Efficient Autonomous Driving

一、介绍 VAD是华科团队设计的一个端到端无人驾驶框架&#xff0c;针对传统的无人驾驶框架的模块化设计的问题&#xff0c;该算法使用向量化的策略进行了端到端的实现。传统的模块化设计使得感知模块完全依赖于感知模块的计算结果&#xff0c;这一解耦实际上从规划模块的角度损…...

uniapp版本加密货币行情应用

uniapp版本加密货币行情应用 项目概述 这是一个使用uniapp开发的鸿蒙原生应用&#xff0c;提供加密货币的实时行情查询功能。本应用旨在为用户提供便捷、实时的加密货币市场信息&#xff0c;帮助用户随时了解市场动态&#xff0c;做出明智的投资决策。 应用采用轻量级设计&a…...

使用 Java 执行 SQL 语句和存储过程

使用 Java 执行 SQL 语句和存储过程&#xff0c;通常有两种主要的方式&#xff1a;使用 JDBC&#xff08;Java Database Connectivity&#xff09;或者通过框架如 Spring Data JPA、MyBatis 等。 1. 使用 JDBC 执行 SQL 语句 JDBC 是 Java 操作数据库的标准 API。以下是通过 …...

算法系列之深度优先搜索寻找妖怪和尚过河问题的所有方式

在算法学习中&#xff0c;深度优先搜索&#xff08;DFS&#xff09;是一种常用的图搜索算法&#xff0c;通过递归或栈实现&#xff0c;适合路径搜索、连通性、拓扑排序、回溯、生成、环路检测、强连通分量和可达性等问题。本文将介绍如何利用深度优先搜索解决“妖怪和尚过河问题…...

大白话JavaScript闭包实现原理与在实际开发中的应用场景

大白话JavaScript闭包实现原理与在实际开发中的应用场景 答题思路 解释闭包的概念&#xff1a;先简单直白地说明闭包是什么&#xff0c;让读者对闭包有一个初步的认识。阐述闭包的实现原理&#xff1a;详细讲解闭包是如何形成的&#xff0c;涉及到函数作用域、变量的生命周期…...

【redis】数据类型之geo

Redis的GEO数据类型用于存储地理位置信息&#xff08;如经纬度&#xff09;&#xff0c;并提供高效的地理位置查询功能&#xff08;如计算两地距离、搜索附近地点等&#xff09;。其底层基于Sorted Set&#xff08;有序集合&#xff09;实现&#xff0c;通过Geohash编码将经纬度…...

C++后端服务器开发技术栈有哪些?有哪些资源或开源库拿来用?

一、 C后台服务器开发是一个涉及多方面技术选择的复杂领域&#xff0c;特别是在高性能、高并发的场景下。以下是C后台服务器开发的一种常见技术路线&#xff0c;涵盖了从基础到高级的技术栈。 1. 基础技术栈 C标准库 C11/C14/C17/C20&#xff1a;使用现代C特性&#xff0c;如…...

第五次CCF-CSP认证(含C++源码)

第五次CCF-CSP认证 第一道&#xff08;easy&#xff09;思路及AC代码 第二道&#xff08;easy&#xff09;思路及AC代码solution 1solution 2 第三道&#xff08;mid&#xff09;思路及AC代码&#xff08;mid&#xff09; 第一道&#xff08;easy&#xff09; 题目链接 思路及…...

tcp udp区别

TCP&#xff08;传输控制协议&#xff09; 和 UDP&#xff08;用户数据报协议&#xff09; 是两种常用的传输层协议&#xff0c;它们在数据传输方式、可靠性和应用场景等方面有显著区别。以下是它们的主要区别&#xff1a; 1. 连接方式 TCP&#xff1a;面向连接的协议。通信前需…...

驱动 AI 边缘计算新时代!高性能 i.MX 95 应用平台引领未来

智慧浪潮崛起&#xff1a;AI与边缘计算的时代 正悄然深植于我们的日常生活之中&#xff0c;无论是火热的 ChatGPT 与 DeepSeek 语言模型&#xff0c;亦或是 Meta 智能眼镜&#xff0c;AI 技术已经无形地影响着我们的生活。这股变革浪潮并未停歇&#xff0c;而是进一步催生了更高…...

【Keil5教程及技巧】耗时一周精心整理万字全网最全Keil5(MDK-ARM)功能详细介绍【建议收藏-细细品尝】

&#x1f48c; 所属专栏&#xff1a;【单片机开发软件技巧】 &#x1f600; 作  者&#xff1a; 于晓超 &#x1f680; 个人简介&#xff1a;嵌入式工程师&#xff0c;专注嵌入式领域基础和实战分享 &#xff0c;欢迎咨询&#xff01; &#x1f496; 欢迎大家&#xff1…...

Linux 进程管理工具 Supervisor

介绍 Supervisor 是一个用 Python 编写的进程管理工具&#xff0c;旨在帮助你监控和控制多个进程。它特别适用于需要确保某些服务在服务器启动时自动运行&#xff0c;并且在崩溃时自动重启的场景。 写在前面&#xff1a; 因为现在很多第三方的包的最新版本都是基于 python3了…...

问题解决:AttributeError: ‘NoneType‘ object has no attribute ‘text‘

项目环境&#xff1a; 我的环境&#xff1a;Window10&#xff0c;Python3.12&#xff0c;Anaconda3&#xff0c;Pycharm2024.3.4 问题描述&#xff1a; 找不到’text’这个对象 部分代码&#xff1a; Traceback (most recent call last):File "D:\IT DateFiles\PyDate\FQ…...

Hadoop、Hive、Spark的关系

Part1&#xff1a;Hadoop、Hive、Spark关系概览 1、MapReduce on Hadoop 和spark都是数据计算框架&#xff0c;一般认为spark的速度比MR快2-3倍。 2、mapreduce是数据计算的过程&#xff0c;map将一个任务分成多个小任务&#xff0c;reduce的部分将结果汇总之后返回。 3、HIv…...

OneM2M:全球性的物联网标准-可应用于物联网中

OneM2M 是一个全球性的物联网(IoT)标准,旨在为物联网设备和服务提供统一的框架和接口,以实现设备之间的互操作性、数据共享和服务集成。OneM2M 由多个国际标准化组织(如 ETSI、TIA、TTC、ARIB 等)共同制定,目标是解决物联网领域的碎片化问题,提供一个通用的标准,支持跨…...

C++类和对象入门(三)

目录 前言 一、初始化列表 1.1定义 1.2 格式和语法 1.3与在函数内初始化的区别 1.4使用初始化列表的必要性 1.5成员变量默认值的使用&#xff08;C11&#xff09; 1.6初始化的先后顺序 1.7初始化列表的总结 二、类型转换 2.1内置类型转化成类类型 2.2类类型之间的相…...

Ubuntu 下 Docker 企业级运维指南:核心命令与最佳实践深度解析20250309

Ubuntu 下 Docker 企业级运维指南&#xff1a;核心命令与最佳实践深度解析 在当今的数字化时代&#xff0c;Docker 已成为企业应用部署和运维的基石。其轻量级、高效且灵活的容器化技术&#xff0c;为企业带来了前所未有的敏捷性和可扩展性。然而&#xff0c;随着容器化应用的…...

Tensorflow 2.0 GPU的使用与限制使用率及虚拟多GPU

Tensorflow 2.0 GPU的使用与限制使用率及虚拟多GPU 1. 获得当前主机上特定运算设备的列表2. 设置当前程序可见的设备范围3. 显存的使用4. 单GPU模拟多GPU环境 先插入一行简单代码&#xff0c;以下复制即可用来设置GPU使用率&#xff1a; import tensorflow as tf import numpy…...

【PyCharm】Python和PyCharm的相互关系和使用联动介绍

李升伟 整理 Python 是一种广泛使用的编程语言&#xff0c;而 PyCharm 是 JetBrains 开发的专门用于 Python 开发的集成开发环境&#xff08;IDE&#xff09;。以下是它们的相互关系和使用联动的介绍&#xff1a; 1. Python 和 PyCharm 的关系 Python&#xff1a;一种解释型、…...

动态规划:多重背包

本题力扣上没有原题&#xff0c;大家可以去卡码网第56题 (opens new window)去练习&#xff0c;题意是一样的。 56. 携带矿石资源&#xff08;第八期模拟笔试&#xff09; 题目描述 你是一名宇航员&#xff0c;即将前往一个遥远的行星。在这个行星上&#xff0c;有许多不同类…...

AI编程: 一个案例对比CPU和GPU在深度学习方面的性能差异

背景 字节跳动正式发布中国首个AI原生集成开发环境工具&#xff08;AI IDE&#xff09;——AI编程工具Trae国内版。 该工具模型搭载doubao-1.5-pro&#xff0c;支持切换满血版DeepSeek R1&V3&#xff0c; 可以帮助各阶段开发者与AI流畅协作&#xff0c;更快、更高质量地完…...

TensorFlow 的基本概念和使用场景

TensorFlow 是一个由 Google 开发的开源深度学习框架&#xff0c;用于构建和训练机器学习模型。它的基本概念包括以下几点&#xff1a; 张量&#xff08;Tensor&#xff09;&#xff1a;在 TensorFlow 中&#xff0c;数据以张量的形式表示&#xff0c;张量可以是多维数组&#…...