源码:java.lang.ThreadLocal<T>.ThreadLocalMap 源码解析
1. TODO
2. 脑图
Xmind
Edraw
Hexo 地址
👉 http://blog.wangjia.ink/2025/11/16/源码:java.lang.ThreadLocal<T>.ThreadLocalMap源码解析/
3. 基础部分
3.1. ThreadLocal.ThreadLocalMap 概述
ThreadLocal.ThreadLocalMap 是一个具体类,是 ThreadLocal 的静态内部类
ThreadLocal.ThreadLocalMap 是通过 ThreadLocal.ThreadLocalMap->table 存储数据的,该数组是由 Entry 构建的数组。每个 Entry 的 key 必须是 ThreadLocal 类型,而 value 是 Object 类型。因此,我们可以把它简单理解为:
[!NOTE] 注意事项
- 猴哥的烦恼箱
(。•́︿•̀。):
- 为什么
ThreadLocal.ThreadLocalMap要使用ThreadLocal实例作为Key?能不能使用其他类的实例?
- 在一个复杂的
Java应用中,会引入大量第三方依赖,它们内部可能都会使用ThreadLocal存储上下文数据- 如果
Key使用字符串(例如 “myName”),不同依赖可能恰好用到同名的Key,最终导致数据被覆盖- 而使用
ThreadLocal实例作为Key依赖于它的对象地址,因为你即便创建了同名的ThreadLocal实例,它们的对象地址仍然是不同的- 那么到底能不能使用其他类的实例呢?从实现的角度来看,只要是实例,就都能当
Key,当然不限制必须是ThreadLocal实例。但是 Entry 的构造方法被设计的就是使用ThreadLocal实例,所以我们就使用这个好了- 为什么
Thread不直接使用其他的Map,而是使用ThreadLocal.ThreadLocalMap?
- 这主要是为了尽量避免内存泄漏,虽然没有彻底杜绝,但是比其他的
Map要好得多- 因为其他的
Map的Key是强引用,只要线程存活,那么ThreadLocal实例就永远无法被回收- 而
ThreadLocal.ThreadLocalMap的Key是弱引用,可以在ThreadLocal实例不再被使用时被回收- 虽然
ThreadLocal#set、ThreadLocal#get能在Key为null时清理Value,但是这是 “被动清理”,并不可靠ThreadLocal.ThreadLocalMap有没有位置冲突?它是如何解决位置冲突的?
- 有,它是采取 “线性探测” 的方式解决位置冲突的。即 如果
i已经被占用,就尝试i + 1,以此类推…
3.2. ThreadLocal.ThreadLocalMap 使用方式
1 | |
[!NOTE] 注意事项
- 在上述代码中,看起来像是在对
ThreadLocal实例本身进行读写,但真正的逻辑是:通过当前线程找到它所持有的ThreadLocal.ThreadLocalMap,然后在这个Map的Entry[]中,以当前ThreadLocal实例为Key进行读写。- 猴哥的烦恼箱
(。•́︿•̀。)
- 为什么
ThreadLocal实例通常由static final修饰?
- 这主要是为了减少内存占用,因为即便多个
ThreadLocal.ThreadLocalMap使用同一个ThreadLocal实例当Key,但是它们互不影响。所以没必要专门为每一个ThreadLocal.ThreadLocalMap创建一个ThreadLocal实例
3.3. ThreadLocal.ThreadLocalMap 问题爆破
3.3.1. 数据 “脏读”
某线程在处理上一个任务时,向 ThreadLocal 写入了数据,但是任务结束后没有清理。当该线程去处理下一个任务的时候,调用 ThreadLocal#get 会读到上一个任务遗留下来的数据
为了解决这一问题,我们需要任务结束后调用 Thread#remove 删除数据
3.3.2. 内存泄漏
由于 ThreadLocal.ThreadLocalMap 的 Key 是弱引用,而 Value 是强引用。所以当 ThreadLocal 实例被回收后,Key 会变成 null,但是对应的 Value 仍然存在,无法被回收
为了解决这一问题,我们需要任务结束后调用 Thread#remove 删除数据
4. 内部类
4.1. Entry
1 | |
5. 核心属性
1 | |
源码:java.lang.ThreadLocal<T>.ThreadLocalMap 源码解析
https://wangjia5289.github.io/2025/11/16/源码:java.lang.ThreadLocal<T>.ThreadLocalMap源码解析/
