【Java后端】之 ThreadLocal 详解
想象一下,你有一个工具箱,里面放着各种工具。在多人共用这个工具箱的时候,很容易出现混乱,比如有人拿走了你的锤子,或者你找不到合适的螺丝刀。为了避免这种情况,最好的办法就是每个人都有自己独立的工具箱。
Java 的 ThreadLocal 就相当于给每个线程提供了一个这样的“私有小盒子”。每个线程都可以把自己的东西放进去,不用担心被其他线程干扰。

1. 为什么要用 ThreadLocal?
在多线程编程中,经常会遇到多个线程同时访问共享变量的情况。如果没有做好同步控制,就可能会出现数据不一致的问题,也就是所谓的“线程安全问题”。
ThreadLocal 提供了一种解决线程安全问题的方法,它让每个线程都拥有自己的变量副本,避免了共享变量的竞争。
2. ThreadLocal 怎么工作的?
ThreadLocal 并不是真的给每个线程创建了一个独立的变量,而是通过一个巧妙的设计来实现的。
每个线程内部都有一个 ThreadLocalMap,可以把它看作是一个键值对的集合。ThreadLocal 对象本身作为键,而线程的私有变量作为值。
当线程调用 ThreadLocal.get() 方法时,ThreadLocal 会根据当前线程找到对应的 ThreadLocalMap,然后根据自身作为键取出对应的值。这样就实现了每个线程访问自己私有变量的目的。
3. 如何使用 ThreadLocal?
使用 ThreadLocal 非常简单,通常分为三步:
-
创建 ThreadLocal 对象: 就像创建一个普通的对象一样,例如 ThreadLocal<String> userName = new ThreadLocal<>();,这里 String 表示私有变量的类型。
-
设置值: 使用 userName.set("张三"); 方法,把“张三”这个字符串放到当前线程的“小盒子”里。
-
获取值: 使用 String name = userName.get(); 方法,从当前线程的“小盒子”里取出值。
ThreadLocal 的 常用方法:
| public API | 描述 |
|---|---|
| set(T) | 设置当前线程的副本 |
| T get() | 获取当前线程的副本 |
| void remove() | 移除当前线程的副本 |
| ThreadLocal<S> withInitial(Supplier<S>) | 创建 ThreadLocal 并指定缺省值创建工厂 |
| protected API | 描述 |
| T initialValue() | 设置缺省值 |
4. 举个栗子
假设一个 Web 应用,每个用户请求都会由一个独立的线程处理。我们可以使用 ThreadLocal 来存储用户的登录信息:
private static final ThreadLocal<String> USER_ID = new ThreadLocal<>();public void processRequest(String userId) {USER_ID.set(userId); // 将用户 ID 存储到 ThreadLocal 中// ... 处理请求 ...String currentUserId = USER_ID.get(); // 获取当前线程的用户 ID// ...USER_ID.remove(); // 使用完毕后清除值
}
5. 内存泄漏的坑
ThreadLocal 使用不当可能会导致内存泄漏。这是因为 ThreadLocalMap 中的键是弱引用,而值是强引用。如果 ThreadLocal 对象被垃圾回收了,但是线程还在运行,那么 ThreadLocalMap 中的值就无法被回收,导致内存泄漏。
为了避免这种情况,最好在使用完 ThreadLocal 后手动调用 remove() 方法清除值,就像上面的例子一样。
6. InheritableThreadLocal:子线程也能继承“小盒子”
InheritableThreadLocal 可以让子线程继承父线程的“小盒子”。也就是说,子线程可以访问父线程设置的线程局部变量。
7. 总结
ThreadLocal 就像给每个线程提供了一个私有的“小盒子”,可以用来存储线程私有的数据,避免线程安全问题。使用起来很简单,但是要注意内存泄漏的坑,记得用完后调用 remove() 方法清理。 选择使用 ThreadLocal 还是其他同步机制,需要根据具体情况进行权衡。 如果只是简单的共享数据,同步机制可能更简单直接。 如果需要维护每个线程独立的数据副本,ThreadLocal 则是更好的选择。
希望这个更通俗易懂的解释能够帮助你理解 ThreadLocal。下期见,谢谢~
相关文章:
【Java后端】之 ThreadLocal 详解
想象一下,你有一个工具箱,里面放着各种工具。在多人共用这个工具箱的时候,很容易出现混乱,比如有人拿走了你的锤子,或者你找不到合适的螺丝刀。为了避免这种情况,最好的办法就是每个人都有自己独立的工具箱…...
2.链表(代码随想录——python版本)
2.链表(代码随想录——python版本) 链表的概念: 链表是由指针串联在一起的线性结构,一个节点(node)由两部分组成: 数据域——用来存储数据;指针域——用来指向下一个节点…...
6个解决“由于找不到vcruntime140_1.dll无法继续执行代码”问题的方法
vcruntime140_1.dll丢失的问题在Windows操作系统中相对常见,它通常与Microsoft Visual C Redistributable有关。本文将详细解读vcruntime140_1.dll丢失的原因、解决方法以及预防措施,帮助用户更好地应对这一问题。 一,vcruntime140_1.dll文件…...
常用数据库获取表,视图,列,索引信息
一、分页获取数据库用户的所有表 (1)、Oracle,OceanBase(Oracle内核版),DM 使用ALL_TABLES,需要添加当前用户作为查询条件 select a3.* from (select a2.* from (select a1.*, rownum rn1 from ( select t1.table_name, t2.comments fro…...
架构设计笔记-16-嵌入式系统架构设计理论与实践
目录 知识要点 嵌入式微处理器 存储器(memory) 内(外)总线逻辑 嵌入式操作系统(Embedded Operating System,EOS) 通用中间件 嵌入式中间件的一般架构 典型嵌入式中间件系统 案例分析 1…...
SpringSecurity使用介绍
1、SpringSecurity 1.1 SpringSecurity简介 Spring Security是基于Spring的安全框架,提供了包含认证和授权的落地方案;Spring Security底层充分利用了Spring IOC和AOP功能,为企业应用系统提供了声明式安全访问控制解决方案;SpringSecurity可…...
# Js 回调函数
Js 回调函数 文章目录 Js 回调函数回调函数的定义和使用回调函数的常见用途异步操作事件处理 回调函数的优点和缺点优点缺点 回调地狱解决回调地狱的方法使用 Promise使用 async/await 应用函数式编程中的回调函数高阶函数函数柯里化 异步编程中的回调函数回调函数的错误处理传…...
COOLSHELL文章:从Code Review 谈如何做技术【阅读笔记】
从Code Review 谈如何做技术原文链接:https://coolshell.cn/articles/11432.html#google_vignette 工程师需要有责任心和修养,不是做出来就了事,而是要做漂亮。 这也是山寨和工业的区别,只以做出来为标准是劳动密集型的装配生产线…...
3.1.1 ReactOS系统中二叉树创建一个MEMORY_AREA节点
二叉树中创建一个MEMORY_AREA节点: 二叉树中创建一个MEMORY_AREA节点: MmCreateMemoryArea() 参数AddressSpace是MADDRESS SPACE结构指针,所指向的数据结构代表着一个进程的用 户空间。 参数BaseAddress是个指针,用来给定和返回内…...
三、Linux 安装全攻略
Linux 安装全攻略 在当今的科技时代,Linux 操作系统以其稳定性、安全性和高度的可定制性而备受青睐。本文将详细介绍 Linux 的安装过程,包括关键步骤和下载资源获取方式,帮助你顺利踏上 Linux 之旅。 一、为什么选择 Linux Linux 有许多优…...
Ansible自动化工具
一、Ansible概述 1.1 什么是Ansible Ansible 是一个开源的自动化工具,用于配置管理、应用程序部署和任务自动化。它让你可以通过编写简单的 YAML 文件(剧本,Playbooks),轻松管理和配置多个服务器。Ansible 的特点是无…...
Flutter Container组件
Over the past few years, I’ve been fortunate to collaborate with interior designers, and there’s a distinct flair to their approach to crafting captivating interiors. It’s not just about arranging furniture randomly; they meticulously plan layouts, sele…...
IPv6 DNS简介
IPv6网络中的每台主机都是由IPv6地址来标识的,用户只有获得待访问主机的IPv6地址,才能够成功实现访问操作。对于用户来讲,记住主机的IPv6地址是相当困难的,因此设计了一种字符串形式的主机命名机制,这就是域名系统。用…...
【Python-AI篇】数据结构和算法
1. 算法概念 1.1 什么是数据结构 存储,组织数据的方式 1.2 什么是算法 实现业务目的的各种方法和思路算法是独立的存在,只是思想,不依附于代码和程序,可以使用不同语言实现(java,python,c&a…...
VideoCLIP-XL:推进视频CLIP模型对长描述的理解
摘要 对比语言-图像预训练(CLIP)已被广泛研究并应用于众多领域。然而,预训练过程中对简短摘要文本的重视阻碍了CLIP理解长描述的能力。在视频方面,这个问题尤为严重,因为视频通常包含大量详细内容。在本文中ÿ…...
【vue】vue-router_ vue3路由管理器
代码获取 vue-router_ vue3路由管理器 ⼀、基本介绍 1. 单⻚应⽤程序介绍 1.1 概念 单⻚应⽤程序:SPA(Single Page Application)是指所有的功能都在⼀个HTML⻚⾯上实现 1.2 具体⽰例 单⻚应⽤⽹站: ⽹易云⾳乐 https://music.163.com/ 多⻚应⽤⽹…...
昇思MindSpore进阶教程--Diffusion扩散模型(上)
大家好,我是刘明,明志科技创始人,华为昇思MindSpore布道师。 技术上主攻前端开发、鸿蒙开发和AI算法研究。 努力为大家带来持续的技术分享,如果你也喜欢我的文章,就点个关注吧 正文 关于扩散模型(Diffusi…...
Nginx:proxy_pass指令
proxy_pass 指令在 Nginx 中是实现反向代理和负载均衡的重要指令。 一. 反向代理 在反向代理的场景下,proxy_pass 指令用于将接收到的请求转发给另一个后端服务器。后端服务器地址可以是 IP 地址加端口、域名加端口、或者一个完整的 URL。 注意事项 proxy_pass …...
【AI学习】Mamba学习(十):HiPPO总结
前面用五篇文章陆续学了HiPPO框架。 这里再进行一下总结。 总结 HiPPO,高阶多项式投影,high-order polynomial projection operators 为了解决从序列数据中建模和学习的问题,尤其是长序列,十万甚至百万长度的序列,使…...
AI编程新纪元:Cursor与V0引领的技术变革
#1024程序员节 | 征文# AI编程新纪元:Cursor与V0引领的技术变革 作为一名SAP业务顾问,虽然我懂一些ABAP开发,但是我对于前后端开发是完全不懂的,我一直对前后端开发怀有浓厚兴趣,总想着自己能开发出一些好玩的东西&…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
C++_哈希表
本篇文章是对C学习的哈希表部分的学习分享 相信一定会对你有所帮助~ 那咱们废话不多说,直接开始吧! 一、基础概念 1. 哈希核心思想: 哈希函数的作用:通过此函数建立一个Key与存储位置之间的映射关系。理想目标:实现…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南
在RK3588上搭建ROS1环境:创建节点与数据可视化实战指南 背景介绍完整操作步骤1. 创建Docker容器环境2. 验证GUI显示功能3. 安装ROS Noetic4. 配置环境变量5. 创建ROS节点(小球运动模拟)6. 配置RVIZ默认视图7. 创建启动脚本8. 运行可视化系统效果展示与交互技术解析ROS节点通…...
