浏览 15868 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-04-18
最后修改:2011-04-26
真正关键的类是它的内部类ThreadLocalMap,ThreadLocal 基本上相当于一个代理,或者算是Facade模式的应用,还没想清楚这种设计的妙处。(经过分析,这种安排与弱引用的特性有关) 2.同时,Thread类中包含一个ThreadLocalMap类型的成员变量。 3.ThreadLocalMap的实现原理跟HashMap差不多,内部有一个Entry数组,一个Entry通常至少包括key,value, 查找时通过一定的运算规则运算Key的HASH值,来得到Entry在数组中的位置,进而得到相应的value。但是比较特殊的是, <1>这个Entry继承了WeakReference, static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } } 注意super(K) 这句,它实际上真正弱引用的是ThreadLocal对象。 <2>同时它的成员的key也一直是负责管理它的ThreadLocal对象。 好了,至此,描述一下三者之间的结构: ThreadLocal 负责管理ThreadLocalMap,包括插入,删除 等等,key就是ThreadLocal对象自己,同时,很重要的一点,就ThreadLocal把map存储在当前线程对象里面。看一下ThreadLocal的get,set方法就一目了然 get(): public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } set(): public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } 现在让我们站在线程的角度来看看三者之间如何互动: 假设 TA,TB 线程, 其中TA线程分别在 LA,LB ThreadLocal对象 分别插入 VA,VB 值对象, TB 在 LA,LC 对象中插入VA,VC 值对象, 则,TA 线程的ThreadLocalMap,存储 weak-reference(LA)-VA,wr(LB)-VB 两组值, TB 线程里的ThreadLocalMap存储 wr(LA)-VA,wr(LC)-VC 。 为什么在ThreadLocalMap 中弱引用ThreadLocal对象呢,当然是从线程内存管理的角度出发的。 使用弱引用,使得ThreadLocalMap知道ThreadLocal对象是否已经失效,一旦该对象失效,也就是成为垃圾,那么它所操控的Map里的数据也就没有用处了,因为外界再也无法访问,进而决定插除Map中相关的值对象,Entry对象的引用,来保证Map总是保持尽可能的小。 总之,线程通过ThreadLocal 来给自己的map 添加值,删除值。同时一旦ThreadLocal本身成为垃圾,Map也能自动清除该ThreadLocal所操控的数据。 引用 /** * Heuristically scan some cells looking for stale entries. * This is invoked when either a new element is added, or * another stale one has been expunged. It performs a * logarithmic number of scans, as a balance between no * scanning (fast but retains garbage) and a number of scans * proportional to number of elements, that would find all * garbage but would cause some insertions to take O(n) time. 这样,通过设计一个代理类ThreadLocal,保证了我们只需要往Map里面塞数据,无需担心清除,这是普通map做不到的, 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-04-19
ThreadLocal应用在事物管理上比较多。
|
|
返回顶楼 | |
发表时间:2011-04-19
http://www.iteye.com/topic/103804
看了这个贴子,原来1.3以前map并不是分布在每个线程对象里的。将map分开以后提高了速度,因为map变小了。 |
|
返回顶楼 | |
发表时间:2011-04-21
最后修改:2011-04-21
引用 使得线程知道ThreadLocal对象是否已经失效,从而决定插除Map中相关的值对象,Entry对象的引用。
挑个刺,这个好像描述的不准确哈 |
|
返回顶楼 | |
发表时间:2011-04-21
最后修改:2011-04-21
iq527 写道 引用 使得线程知道ThreadLocal对象是否已经失效,从而决定插除Map中相关的值对象,Entry对象的引用。
挑个刺,这个好像描述的不准确哈 贴上jdk6的源代码: /** * Expunge a stale entry by rehashing any possibly colliding entries * lying between staleSlot and the next null slot. This also expunges * any other stale entries encountered before the trailing null. See * Knuth, Section 6.4 * * @param staleSlot index of slot known to have null key * @return the index of the next null slot after staleSlot * (all between staleSlot and this slot will have been checked * for expunging). */ private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; // expunge entry at staleSlot tab[staleSlot].value = null; tab[staleSlot] = null; size--; // Rehash until we encounter null Entry e; int i; for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal k = e.get(); if (k == null) { e.value = null; tab[i] = null; size--; } else { int h = k.threadLocalHashCode & (len - 1); if (h != i) { tab[i] = null; // Unlike Knuth 6.4 Algorithm R, we must scan until // null because multiple entries could have been stale. while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } } return i; } 注意这句 ThreadLocal k = e.get(), 弱引用的典型用法,用来判断该对象是否已经失效了,或者被垃圾回收器回收了。 |
|
返回顶楼 | |