100%保证线程安全,还有这种黑科技?

简介: 大家好,我是指北君。今天学习了ThreadLocal相关的知识,发现原来道哥(Doug Lea)也用ThreadLocal。既然大师们都喜欢用的,我们必须得研究起来。大师的背影总是需要追随。

那么指北君给大家安排上了,如果你拥有了Java中的ThreadLocal,那麽你可以创建一个只允许同一个线程读写的变量。因此,即使两个线程执行了相同的代码,并且引用了相同的ThreadLocal变量,这两个线程也无法看到彼此的ThreadLocal。可以说ThreadLocal提供了一种代码线程安全的的简单方法。

下面我们就来看看道哥都用的ThreadLocal。

1 ThreadLocal你来自哪里

60.png

又是并发大佬们的杰作,膜拜一下。怪不得道哥也爱用,自己设计的类总得用用。下面来看看基本内容与用法吧。


61.jpg


2 ThreadLocal原理


首先请看男神们的介绍

“This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).”

“此类提供了thread-local变量。这些变量不同于普通的类似变量,因为访问某个变量(通过其 get 或 set 方法)的每个线程都有自有的,独立初始化的变量副本,ThreadLocal实例通常是希望将状态与线程(例如,用户ID或事务ID)关联的类中的私有静态字段。”

通过老爷子们的描述,指北君大概也知道了ThreadLocal的推荐使用场景,

  1. ThreadLocal提供了一种访问某个特有变量的方法 访问到的变量属于当前线程,同一线程在任何地方都能访问同一个线程特有变量。
  2. 推荐定义为 private static 类型,但是Doug Lea老爷子在ThreadLocalRandom 和 ReentrantReadWriteLock 中使用了 private static final 类型。(肯定是当年写简介的时候手抖了)


2.1 Thread中如何存储


既然是线程的变量,自然是存在Thread对象中的一个变量了,但是它是通过ThreadLocal这个类来维护的。



62.png

ThreadLocal中有一个内部类来ThreadLocalMap来维护这些线程本地变量,

63.png


ThreadLocalMap中的Entry结构如下,是一种key为弱引用(其目的就是Entry对象在GC时容易回收)的hash map,其中key总是ThreadLocal。

64.png


2.2 常用方法 get,set,remove 详解


  • get() 此方法是ThreadLocal最重要的方法之一,该方法返回此线程局部变量的当前线程副本中的值。大概可分为以下几步:
    (1) 先获取当前线程,然后再从线程中得到ThreadLocalMap。
    (2) 然后使用ThreadLocal对象的threadLocalHashCode进行散列计算,得到一个数组的index
    (3) 从Table数组中得到Entry,再对比Entry的key是不是和当前的ThreadLocal相等,如果相等就返回此Entry的value
    (4) 如果上一步中得到的Entry与当前ThreadLocal不相等,则会在方法getEntryAfterMiss中进行遍历Entry数组table中的每一个元素,如果找不到就返回null。而且在遍历的过程中会顺便清理一下废弃的Entry。

下面可以看一下get方法的具体代码。

65.png66.png

  • set(T value) 此方法将此线程局部变量的当前线程副本中的值设置为指定值。

set线程本地变量步骤如下:

(1) 首先依然是获取此线程的ThreadLocalMap

(2) Map不为null时往map中插入数据,否侧创建map并插入数据

(3) 具体的set方法依然是先遍历Entry数组中所有的的Entry,然后依次对比每个Entry的key是否等于当前ThreadLocal,如果相等则直接替换现有Entry的value。如果Entry的Key为null,则立马清理废弃的Entry,并用新的Entry来替换此卡槽。

(4) 如果遍历完都没有return,则在在table中相应卡槽下新建Entry对象

67.png68.png

remove() remove则相对简单,直接遍历ThreadLocalMap中Entry数组table,找到对应的Entry,将Entry的key置为null,然后再清理相应的Entry。


69.png


3 Java中使用的ThreadLocal


Java中有哪些源码使用了ThreadLocal。

ThreadLocalRandom 中使用计算nextGaussian值时有使用到ThreadLocal。

InheritableThreadLocal继承了ThreadLocal,线程中使用inheritableThreadLocals这个map存储线程本地变量。和ThreadLocal的区别就是子线程依然可以访问到父线程的线程本地变量,实际应用中也推荐InheritableThreadLocal

ReentrantReadWriteLock中线程读写锁的计数器使用了ThreadLocal,其目的是记录每个线程获取读写锁的次数



70.png


4 如何使用ThreadLocal


ThreadLocal非常适合存储非线程安全的对象,并且不需要跨线程共享对象。很多需要线程隔离的操作都可以尝试使用它。

ThreadLocal也非常适合在Web应用程序中使用,典型的应用就是在Web请求进来一开始就将请求状态存储在ThreadLocal中,然后参与处理的任何组件均可访问该状态。

以下是一个ThreadLocal示例:

具体使用就是配合interceptor或者filter在线程刚开始执行的时候存储SessionContext,线程执行过程中可以随时访问该变量。然后在线程执行结束的时候再调用remove()方法移除,防止内存泄漏。


image.png

总结

本文介绍了ThreadLocal的原理以及解析了常用方法的实现逻辑,以及在ThreadLocal一些应用。在一步步梳理的过程中,果然看到了以往忽略的各种细节,最后给出了一个小Case。并发编程大神道哥.李都在用的ThreadLocal,不妨在自己的项目中偷偷用上,保证丝滑舒适。

我是指北君,操千曲而后晓声,观千剑而后识器。感谢各位人才的:点赞、收藏和评论,我们下期更精彩!




相关文章
|
1天前
|
云安全 数据采集 人工智能
古茗联名引爆全网,阿里云三层防护助力对抗黑产
阿里云三层校验+风险识别,为古茗每一杯奶茶保驾护航!
古茗联名引爆全网,阿里云三层防护助力对抗黑产
|
5天前
|
Kubernetes 算法 Go
Kubeflow-Katib-架构学习指南
本指南带你深入 Kubeflow 核心组件 Katib,一个 Kubernetes 原生的自动化机器学习系统。从架构解析、代码结构到技能清单与学习路径,助你由浅入深掌握超参数调优与神经架构搜索,实现从使用到贡献的进阶之旅。
278 139
|
5天前
|
人工智能 中间件 API
AutoGen for .NET - 架构学习指南
《AutoGen for .NET 架构学习指南》系统解析微软多智能体框架,涵盖新旧双架构、核心设计、技术栈与实战路径,助你从入门到精通,构建分布式AI协同系统。
296 142
|
16天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
11天前
|
缓存 并行计算 PyTorch
144_推理时延优化:Profiling与瓶颈分析 - 使用PyTorch Profiler诊断推理延迟,优化矩阵运算的独特瓶颈
在2025年的大模型时代,推理时延优化已经成为部署LLM服务的关键挑战之一。随着模型规模的不断扩大(从数亿参数到数千亿甚至万亿参数),即使在最先进的硬件上,推理延迟也常常成为用户体验和系统吞吐量的主要瓶颈。
359 147
|
5天前
|
人工智能 移动开发 自然语言处理
阿里云百炼产品月刊【2025年9月】
本月通义千问模型大升级,新增多模态、语音、视频生成等高性能模型,支持图文理解、端到端视频生成。官网改版上线全新体验中心,推出高代码应用与智能体多模态知识融合,RAG能力增强,助力企业高效部署AI应用。
301 1
|
11天前
|
机器学习/深度学习 存储 缓存
92_自我反思提示:输出迭代优化
在大型语言模型(LLM)应用日益普及的今天,如何持续提升模型输出质量成为了业界关注的核心问题。传统的提示工程方法往往依赖一次性输入输出,难以应对复杂任务中的多轮优化需求。2025年,自我反思提示技术(Self-Reflection Prompting)作为提示工程的前沿方向,正在改变我们与LLM交互的方式。这项技术通过模拟人类的自我反思认知过程,让模型能够对自身输出进行评估、反馈和优化,从而实现输出质量的持续提升。
442 136
|
15天前
|
存储 人工智能 搜索推荐
终身学习型智能体
当前人工智能前沿研究的一个重要方向:构建能够自主学习、调用工具、积累经验的小型智能体(Agent)。 我们可以称这种系统为“终身学习型智能体”或“自适应认知代理”。它的设计理念就是: 不靠庞大的内置知识取胜,而是依靠高效的推理能力 + 动态获取知识的能力 + 经验积累机制。
415 135
|
15天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
545 133
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话