Thread、ThreadLocal、ThreadLocalMap

参考:

Java 并发常见面试题总结(下) | JavaGuide

ThreadLocal 详解 | JavaGuide

通常情况下,我们创建的变量可以被任何一个线程访问和修改。这在多线程环境中可能导致数据竞争和线程安全问题。那么,如果想让每个线程都有自己的专属本地变量,该如何实现呢?

JDK 中提供的 ThreadLocal 类正是为了解决这个问题。ThreadLocal 类允许每个线程绑定自己的值。

ThreadLocalMap

每个 Thread 对象内部都有一个成员变量  ThreadLocalMap。

ThreadLocalMap 是一个定制哈希表,定义在 ThreadLocal 内部,key 是 ThreadLocal 的实例(弱引用),value 是 set 进去的值(强引用)。

ThreadLocal

ThreadLocal 相当于一个工具类,对外暴露 get、set、remove 方法,在内部再通过 currentThread 拿到当前线程的 ThreadLocalMap,再操作这个 map。

存储结构示例:

Thread t1
├── threadLocals (ThreadLocalMap)
│   ├── Entry

\[0\]

: key=ThreadLocal@A(弱引用), value=UserObj@X
│   ├── Entry

\[1\]

: key=ThreadLocal@B(弱引用), value=UserObj@Y
│   └── …

ThreadLocal 缺点

  1. 内存泄漏

    • 柜子钥匙(ThreadLocal 对象)是弱引用,容易被垃圾回收。
    • 但柜子里面的value 是强引用,如果线程一直不死(如线程池复用),value 就永远占着内存 。
    • 解决:用完一定finally { threadLocal.remove(); }
  2. 脏读

    • 线程池把同一条线程反复租给不同任务,上一次任务留下的 value 被下一次任务“误拿”,出现数据串味
    • 解决:同上,任务开始前先 remove()
  3. 不可继承

    • 主线程的 ThreadLocal 值,子线程默认看不见(父子线程不同柜子)。
    • 若需要传递,用 InheritableThreadLocal,但也只能传创建子线程那一刻的“快照” 。
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计