ThreadLocal是大家比较常用到的,在多线程下存储线程相关数据十分合适。可是很多时候我们并没有深入去了解它的原理。

首选提出几个问题,稍后再针对这些问题一一解答。

  1. 提到ThreadLocal,大家常说ThreadLocal是弱引用,那么ThreadLocal究竟是如何实现弱引用的呢?
  2. ThreadLocal是如何做到可以当做线程局部变量的呢?
  3. 大家创建ThreadLocal变量时,为什么都要用static修饰?
  4. 大家争论不止的ThreadLocal内存泄漏是什么鬼?

进入正题,先简单了解下ThreadLocal 和 Thread,ThreadLocal的类结构:

 

 可以看到,ThreadLocal有个内部类ThreadLocalMap,ThreadLocalMap又有个内部类Entry。

Thread类有这样一段源码:

复制代码
class Thread implements Runnable {      ...省略若干代码      /* ThreadLocal values pertaining to this thread. This map is maintained      * by the ThreadLocal class. */     ThreadLocal.ThreadLocalMap threadLocals = null;      /*      * InheritableThreadLocal values pertaining to this thread. This map is      * maintained by the InheritableThreadLocal class.      */     ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
复制代码

 

 通过Thread源码我们了解到,Thread持有的对象是ThreadLocalThreadLocalMap,这一点特别重要,线程相关数据都是通过ThreadLocalMap存储的,而不是ThreadLocal。

此时我们得到的结论如下图所示:

Thread的threadLocals属性直接关联的ThreadLocal.ThreadLocalMap,和ThreadLocal没有丝毫关系

 

那么ThreadLocal是做什么的呢?其实ThreadLocal可以看做线程操作ThreadLocalMap的工具类,ThreadLocal暴漏了两个公共方法get()和set(T)用来获取和设置ThreadLocalMap。

了解一下set方法源码:

 

复制代码
1     public void set(T value) { 2         Thread t = Thread.currentThread(); 3         ThreadLocalMap map = getMap(t); 4         if (map != null) 5             map.set(this, value); 6         else7             createMap(t, value); 8     }
复制代码

 

 

 

 

 

 

 从源码第五行我们可以得到两个重要的信息:

  • 获取ThreadLocalMap时,使用了当前Thread对象 t 作为参数。

    getMap(t)方法的实现很简单:

      

    ThreadLocalMap getMap(Thread t) {         return t.threadLocals;     }

 

    它返回的是Thread的 threadLocals 属性,代码上验证了: