1. ThreadLocal 核心概念解析
在 Java 并发编程中,ThreadLocal 是一个独特而强大的工具。它不像 synchronized 或 Lock 那样通过加锁来控制共享资源的访问,而是采用了一种完全不同的思路——为每个线程创建变量的独立副本。
1.1 并发安全的两大策略
当多个线程需要访问共享变量时,我们通常有两种策略来保证线程安全:
-
时间换空间:synchronized 和 Lock 采用这种策略。所有线程共享同一个变量,通过控制访问顺序来保证安全。这种方式节省内存但可能影响性能。
-
空间换时间:ThreadLocal 采用这种策略。每个线程都有自己的变量副本,互不干扰。这种方式消耗更多内存但访问速度更快。
实际开发中选择哪种策略,需要根据具体场景权衡。对于频繁读写且线程间不需要共享状态的变量,ThreadLocal 通常是更好的选择。
1.2 ThreadLocal 的内部实现
ThreadLocal 的核心在于 Thread 类中的 threadLocals 字段,这是一个 ThreadLocalMap 类型的变量。每个线程都维护着自己的 ThreadLocalMap,其中存储着该线程所有的 ThreadLocal 变量。
ThreadLocalMap 的实现有几个关键点需要注意:
- 数据结构:使用数组而非 HashMap 的链表/红黑树结构
- 哈希算法:采用斐波那契散列,提高分布均匀性
- 冲突解决:线性探测法(开放地址法的一种)
java复制// Thread 类中的相关字段
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. ThreadLocalMap 深度剖析
2.1 数据结构设计
ThreadLocalMap 是一个定制化的哈希表,专门为 ThreadLocal 设计。与 HashMap 相比,它有以下特点:
- 只使用数组存储,没有链表或红黑树
- 初始容量为16,扩容阈值为长度的2/3
- 使用线性探测法解决哈希冲突
- key 是弱引用的 ThreadLocal 实例
2.2 set() 方法实现
set() 方法是 ThreadLocalMap 的核心方法之一,其执行流程值得深入研究:
- 计算初始位置:hashCode & (len-1)
- 线性探测查找合适的位置:
- 找到空位直接插入
- 遇到相同 key 则替换值
- 遇到过期条目则触发清理
- 检查是否需要扩容
java复制private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) {
