深入解析ThreadLocal( 八 )

此方法的作用是 返回该线程局部变量的初始值 。
(1) 这个方法是一个延迟调用方法 , 从上面的代码我们得知 , 在set方法还未调用而先调用了get方法时才执行 , 并且仅执行1次 。
(2)这个方法缺省实现直接返回一个null 。
(3)如果想要一个除null之外的初始值 , 可以重写此方法 。 (备注: 该方法是一个protected的方法 , 显然是为了让子类覆盖而设计的)
5. ThreadLocalMap源码分析在分析ThreadLocal方法的时候 , 我们了解到ThreadLocal的操作实际上是围绕ThreadLocalMap展开的 。 ThreadLocalMap的源码相对比较复杂, 我们从以下三个方面进行讨论 。
5.1 基本结构ThreadLocalMap是ThreadLocal的内部类 , 没有实现Map接口 , 用独立的方式实现了Map的功能 , 其内部的Entry也是独立实现 。
(1) 成员变量
/*** 初始容量 —— 必须是2的整次幂*/private static final int INITIAL_CAPACITY = 16;/*** 存放数据的table , Entry类的定义在下面分析* 同样 , 数组长度必须是2的整次幂 。*/private Entry[] table;/*** 数组里面entrys的个数 , 可以用于判断table当前使用量是否超过阈值 。*/private int size = 0;/*** 进行扩容的阈值 , 表使用量大于它的时候进行扩容 。*/private int threshold; // Default to 0跟HashMap类似 , INITIAL_CAPACITY代表这个Map的初始容量;table 是一个Entry 类型的数组 , 用于存储数据;size 代表表中的存储数目; threshold 代表需要扩容时对应 size 的阈值 。
链接:
来源:简书
著作权归作者所有 。 商业转载请联系作者获得授权 , 非商业转载请注明出处 。
(2) 存储结构 - Entry
/* * Entry继承WeakReference , 并且用ThreadLocal作为key. * 如果key为null(entry.get() == null) , 意味着key不再被引用 ,* 因此这时候entry也可以从table中清除 。*/static class Entry extends WeakReference> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal k, Object v) {super(k);value = http://kandian.youth.cn/index/v;}}在ThreadLocalMap中 , 也是用Entry来保存K-V结构数据的 。 不过Entry中的key只能是ThreadLocal对象 , 这点在构造方法中已经限定死了 。
另外 , Entry继承WeakReference , 也就是key(ThreadLocal)是弱引用 , 其目的是将ThreadLocal对象的生命周期和线程生命周期解绑 。
5.2 弱引用和内存泄漏有些程序员在使用ThreadLocal的过程中会发现有内存泄漏的情况发生 , 就猜测这个内存泄漏跟Entry中使用了弱引用的key有关系 。 这个理解其实是不对的 。
我们先来回顾这个问题中涉及的几个名词概念 , 再来分析问题 。
(1) 内存泄漏相关概念

  • Memory overflow:内存溢出 , 没有足够的内存提供申请者使用 。
  • Memory leak: 内存泄漏是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放 , 造成系统内存的浪费 , 导致程序运行速度减慢甚至系统崩溃等严重后果 。 内存泄漏的堆积终将导致内存溢出 。
(2) 弱引用相关概念
Java中的引用有4种类型: 强、软、弱、虚 。 当前这个问题主要涉及到强引用和弱引用:
强引用(“Strong” Reference) , 就是我们最常见的普通对象引用 , 只要还有强引用指向一个对象 , 就能表明对象还“活着” , 垃圾回收器就不会回收这种对象 。
弱引用(WeakReference) , 垃圾回收器一旦发现了只具有弱引用的对象 , 不管当前内存空间足够与否 , 都会回收它的内存 。
(3) 如果key使用强引用
假设ThreadLocalMap中的key使用了强引用 , 那么会出现内存泄漏吗?


推荐阅读