ThreadLocal,ThreadLocalMap,Thread 的相互关系以及设计原理分析
发布日期:2021-09-16 12:19:52 浏览次数:3 分类:技术文章

本文共 4185 字,大约阅读时间需要 13 分钟。

一句话,ThreadLocal并不是把线程作为key,值作为value的类似一种HashMap的东西。而是每个Thread里面都有一个ThreadLocalMap的集合,ThreadLocal只是操作每个线程的ThreadLocalMap而已。

转:http://www.iteye.com/topic/1007515

1.ThreadLocal. 
真正关键的类是它的内部类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
{ /** 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做不到的, 
贴上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(), 弱引用的典型用法,用来判断该对象是否已经失效了,或者被垃圾回收器回收了。

转载地址:https://blog.csdn.net/wxwzy738/article/details/42194223 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:正确理解ThreadLocal
下一篇:Java中单例模式和静态类的区别

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月22日 13时01分04秒