ThreadLocal讲义

1. ThreadLocal 是什么

ThreadLocal 是 Java 中的一个线程本地变量工具类,它提供了线程级别的变量存储能力。每个线程都可以通过 ThreadLocal 获取到自己独有的变量副本,不同线程之间的变量互不干扰

简单来说,ThreadLocal 就像是为每个线程配备了一个专属的 “储物柜”,线程可以将自己的私有数据存入其中,并且只能访问自己存入的数据。

2. ThreadLocal 的作用

ThreadLocal 主要有以下作用:

  • 提供线程私有变量:让每个线程都拥有自己独立的变量副本
  • 解决线程安全问题:避免多线程环境下共享变量的同步问题
  • 简化参数传递:减少多层方法调用时的参数传递,线程内可直接获取所需变量
  • 保存线程上下文信息:如用户身份、请求信息等,方便线程内随时访问

3. 什么时候使用 ThreadLocal

适合使用 ThreadLocal 的场景:

  • 避免方法参数传递链过长:当多个方法需要同一参数时

示例场景:在软件三层架构的开发中,某个数据需要在所有层之间传递并使用,就可以通过ThreadLocal实现。

4. 如何使用 ThreadLocal

基本使用步骤:

  1. 创建 ThreadLocal 实例 (直接new)
  2. 存储线程私有变量 (调用 set(值) 方法)
  3. 获取线程私有变量 (调用 get() 方法)
  4. 清理线程私有变量 (调用 remove() 方法)(非常重要)

5. 使用 ThreadLocal 的注意事项

  1. 必须清理资源:使用完 ThreadLocal 后务必调用 remove() 方法清理数据,避免内存泄漏
  2. 线程池环境需特别注意:线程池中的线程会被复用,若不清理会导致数据混乱
  3. 避免存储大对象:可能导致内存占用过高
  4. 继承性问题:子线程默认无法获取父线程的 ThreadLocal 变量,需使用 InheritableThreadLocal
  5. 不要作为全局变量滥用:过度使用会使代码逻辑变得混乱
  6. 内存泄漏风险:ThreadLocal 中的 Entry 是弱引用,但若不调用 remove (),仍可能导致 value 的内存泄漏

弱引用: 用 WeakReference 类包装的引用,如 new WeakReference<>(obj),只要发生 GC 对象的空间就会被回收。

内存泄漏: 内存泄漏指不再被应用程序使用的对象,却因为仍然被某些 GC Root 引用而无法被垃圾回收,导致内存占用持续增长,最终可能 OutOfMemoryError

6. ThreadLocal 的原理

ThreadLocal 的实现原理主要基于以下几点:

  1. 每个 Thread 维护一个 ThreadLocalMap

    1
    ThreadLocal.ThreadLocalMap threadLocals = null;
  2. ThreadLocalMap 是 ThreadLocal 的内部类

    • 采用数组存储 Entry 对象
    • Entry 的 key 是 ThreadLocal 实例(弱引用)
    • Entry 的 value 是存储的线程私有变量
  3. set () 方法原理

    • 获取当前线程的 ThreadLocalMap
    • 若不存在则创建
    • 以当前 ThreadLocal 为 key,存储值到 map 中
  4. get () 方法原理

    • 获取当前线程的 ThreadLocalMap
    • 以当前 ThreadLocal 为 key,从 map 中获取值
    • 若 map 不存在或无对应值,则调用 initialValue () 初始化
  5. 哈希冲突处理

    • ThreadLocalMap 使用开放地址法解决哈希冲突
    • 而 HashMap 使用链地址法

这种设计使得每个线程都通过自己的 ThreadLocalMap 管理变量,从而保证了线程隔离性。

总结

每个线程内部都有一个”Map集合”,我们创建的ThreadLocal对象,作为了”Map集合”的key使用了,因此多线程之间使用同一个ThreadLocal对象操作值的时候互相不影响!!!(因为每个线程内部都维护了一个线程自己专属的Map集合)

image-20260422164623365