<强>
强>
ThreadLocal是每个线程自己维护的一个存储对象的数据结构,线程间互不影响实现线程封闭。一般我们通过ThreadLocal对象的获?设置方法存取对象。
ThreadLocal的设置方法源码如下
公共空集(T值){ 线程t=Thread.currentThread (); ThreadLocalMap地图=getMap (t);//根据当前线程获得ThreadLocalMap对象 如果(地图!=null) 地图。集(这个值);//如果有则集 其他的 createMap (t值);//否则创建ThreadLocalMap对象 } ThreadLocalMap getMap(线程t) { 返回t.threadLocals; } 空白createMap(线程t, t firstValue) { t。threadlocal=new ThreadLocalMap(这个,firstValue); }
通过getMap方法,可见我们返回的地图实际上是线程对象的threadlocal属性。而这个ThreadLocalMap就是用来存储数据的结构。
<强> ThreadLocalMap介绍强>
ThreadLocalMap是ThreadLocal的核心,定义在ThreadLocal类里的内部类,他维护了一个Enrty数组.ThreadLocal存/取数据都是通过操作Enrty数组来实现的。
Enrty数组作为一个哈希表,将对象通过开放地址方法散列到这个数组中。作为对比,HashMap则是通过链表法将对象散列到数组中。
开放地址法就是元素散列到数组中的位置如果有冲突,再以某种规则在数组中找到下一个可以散列的位置,而在ThreadLocalMap中则是使用线性探测的方式向后依次查找可以散列的位置。
<强>埃内里介绍强>
埃内里在这里我们称之为元素,是散列表中维护的对象单元。
//哈希映射表中的元素使用其引用字段作为键(它始终是ThreadLocal对象)继承WeakReference引用。//注意,零键(即条目。get ()==null)表示不再引用该键,因此可以从表中删除该元素。//这些元素在下面的代码中称为“旧元素”。//这些“旧元素”就是脏对象,因为存在引用不会被GC,//为避免内存泄露需要代码里清理,将引用置为空,那么这些对象之后就会被GC清理。//实际上后面的代码很大程度上都是在描述如何清理“旧元素”的引用 静态类条目延伸WeakReference到这里可能有两个疑问
1,既然要存储的内容是线程独有的对象,为什么不直接在线程里设置一个属性直接存储该对象?或者说为什么要维护一个条目散列表来存储内容并以ThreadLocal对象作为钥匙吗?
答:一个ThreadLocal对象只属于一个线程,但一个线程可以实例化ThreadLocal对象。而ThreadLocalMap维护的数组存储的就是以ThreadLocal实例作为关键的入口对象。
2, ThreadLocalMap中的埃内里为什么要继承weakreference # 63;
答:首先弱引用会在ThreadLocal对象不存在强引用的情况,弱引用对象会在下次GC时被清除。
将ThreadLocal对象作为弱引用目的是为了防止内存泄露。
假设埃内里的关键不是弱引用,即使在我们的代码里threadLocal引用已失效,threadLocal也不会被GC,因为当前线程持有ThreadLocalMap的引用,而ThreadLocalMap持有条目数组的引用,入口对象的关键又持有threadLocal的引,用threadLocal对象针对当前线程可达,所以不会被GC。
而埃内里的关键值threadLocal作为弱引用,在引用失效时会被GC。但即使threadLocal做为弱引用被GC清理,条目[]还是存在条目对象,只是关键为null, vlue对象也还存在,这些都是脏对象。弱引用不单是清理了threadLocal对象,它的另一层含义是可以标识出埃内里[]数组中哪些元素应该被GC(我们这里称为旧元素),然后程序里找出这些条目并清理。
<强> ThreadLocalMap组的方法
强>回到前面提到组的方法,当地图不为空时会调用ThreadLocalMap组的方法。
ThreadLocalMap组的方法描述了如何将值散列到哈希表中,是开放地址法以线性探测方式散列的实现。在成功集值之后,尝试清理一些旧元素,如果没有发现旧元素则判断阈值,确认哈希表是否足够大,是否需要扩容。如果哈希表过于拥挤,获?设置值会发生频繁的冲突,这是不期望的情况.ThreadLocalMap组的方法代码及详细注释如下
深入学习java ThreadLocal的源码知识