深入解析ThreadLocal:原理与实战

5星 · 超过95%的资源 需积分: 49 5 下载量 51 浏览量 更新于2024-08-05 收藏 22KB MD 举报
“ThreadLocal详解,包括其与Thread的关系、ThreadLocalMap的结构、弱引用、方法原理以及清理策略。” **ThreadLocal** 是 Java 中用于线程局部变量的类,它允许每个线程拥有独立的变量副本,从而实现线程间的隔离。ThreadLocal 不是通过继承来实现线程局部变量,而是通过在每个线程内部维护一个 ThreadLocal 变量的副本来达到目的。 ### ThreadLocalMap 和 Thread 与 ThreadLocal 的关系 ThreadLocalMap 是 ThreadLocal 的内部类,它是一个特化的哈希表,用于存储每个线程的 ThreadLocal 变量。当首次调用 ThreadLocal 的 `set()` 方法时,会在当前线程中创建一个 ThreadLocalMap 实例,并将 ThreadLocal 对象作为键,存储的值作为值。这意味着每个线程都有自己的 ThreadLocalMap,而不是所有线程共享一个。 ### ThreadLocalMap 结构 ThreadLocalMap 使用 Entry 类作为它的存储单元,Entry 是一个内部静态类,它的键是 ThreadLocal 对象,值是用户存储的对象。Entry 使用弱引用保存 ThreadLocal 键,目的是在 ThreadLocal 对象不再被引用时,可以被垃圾收集器回收,但需要注意的是,如果值对象仍然被其他引用,Entry 本身不会被回收。 ### ThreadLocalMap 的方法原理 - **set()**: 将指定的值与当前线程的 ThreadLocalMap 关联。它使用线程局部哈希和黄金分割数(HASH_INCREMENT)来计算索引,以实现均匀分布,减少冲突。 - **get()**: 根据当前线程的 ThreadLocalMap 查找对应的值。如果找不到,则返回 null。 - **remove()**: 移除当前线程 ThreadLocalMap 中对应的 Entry,释放对值对象的引用。 ### 清理过期 key 的方式 ThreadLocalMap 有两种清理过期 key 的方式: 1. **启发式清理**:在 ThreadLocal 对象被垃圾收集时,如果其在 ThreadLocalMap 中的引用变为弱引用,那么在下次调用 get() 或 set() 时会尝试清理。 2. **探测式清理**:在每次调用 set()、get() 或 remove() 方法时,检查并移除已经死亡的 ThreadLocal 引用。 ### 扩容触发条件 当 ThreadLocalMap 需要扩容时,通常是在插入新 Entry 且当前索引位置已满的情况下。它会创建一个新的更大的数组,并将旧数组中的元素复制过去。 ### 示例代码分析 在提供的代码中,可以看到 ThreadLocal 的一些关键特性,如 `threadLocalHashCode` 的初始化,它是基于黄金分割数的哈希值,用于提高在 ThreadLocalMap 中的分布均匀性。`nextHashCode()` 方法用于获取下一个哈希值,每次调用增加 HASH_INCREMENT。 ThreadLocal 提供了一种在多线程环境下安全地存储和访问线程局部变量的方法,而 ThreadLocalMap 则是其实现的核心。理解和掌握 ThreadLocal 及其工作原理对于编写高效的并发代码至关重要。