作用

ThreadLocal是解决线程安全问题一个很好的思路,它通过为每个线程提供一个独立的变量副本解决了变量并发访问的冲突问题。在很多情况下,ThreadLocal比直接使用synchronized同步机制解决线程安全问题更简单,更方便,且结果程序拥有更高的并发性。

应用场景

在Java的多线程编程中,为保证多个线程对共享变量的安全访问,通常会使用synchronized来保证同一时刻只有一个线程对共享变量进行操作。这种情况下可以将类变量放到ThreadLocal类型的对象中,使变量在每个线程中都有独立拷贝(弱引用),不会出现一个线程读取变量时而被另一个线程修改的现象。最常见的ThreadLocal使用场景为用来解决数据库连接、Session管理等。

每个线程生成的弱引用副本

每个线程都拥有一个弱引用(WeakReference)副本,该引用是对它的线程局部变量的副本的引用;线程消失后,它的所有线程本地实例副本都将接受垃圾收集(除非存在对这些副本的其他引用)。
源码实现:

  1. static class Entry extends WeakReference<ThreadLocal<?>> {
  2. Object value;
  3. Entry(ThreadLocal<?> k, Object v) {
  4. super(k);
  5. value = v;
  6. }
  7. }

ThreadLocal内存泄漏

内存泄露:程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重。

image.png
每一个 Thread 维护一个 ThreadLocalMap,key 弱引用,外部的 ThreadLocalRef 是 key 的强引用,一旦ThreadLocalRef 为 null,GC 时 key 就会被回收,但是 value 还存在强引用,只有 CurrentThreadRef 为 null时,value 才会被回收。
如果当前线程需要执行很久,这些key为null的Entry的value就会一直存在一条强引用链:

  1. CurrentThreadRef -> CurrentThread -> ThreaLocalMap -> Entry -> value

ThreadLocal类结构

image.png

InheritableThreadLocal

可以让让子线程继承父线程中已经设置的值。

  1. public class InheritableThreadLocal<T> extends ThreadLocal<T> {
  2. protected T childValue(T parentValue) {
  3. return parentValue;
  4. }
  5. ThreadLocalMap getMap(Thread t) {
  6. return t.inheritableThreadLocals;
  7. }
  8. void createMap(Thread t, T firstValue) {
  9. t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
  10. }
  11. }