美文网首页
ThreadLocal

ThreadLocal

作者: HWilliamgo | 来源:发表于2018-08-16 09:45 被阅读12次

    ThreadLocal

    ThreadLocal是一个线程独立存储类,通过他的getset方法,在不同的线程中,可以独立地存取不同的value

    每次回顾Looper源码的时候,都会忘了ThreadLocal是如何实现和工作的,故这次记录下来。

    [TOC]

    工作原理图

    ThreadLocal中的ThreadLocalMap

    首先观察ThreadLocal的结构,有两个静态内部类,其中第二个ThreadLocalMap是他工作原理的最重要的类。

    此时点开Thread类源码:

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    

    会发现Thread引用了一个ThreadLocal.ThreadLocalMap,并且命名为threadLocals。并且这个引用在每一个Thread对象中只有一个。这样的设计使得每个Thread对象都有一个自己的Map

    Entry extends WeakRefernce

    再回到ThreadLocalMap中。

    如果看过HashMap或者LinkedHashMap源码应该会对这个Entry的设计很熟悉。代码为:

    static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;
        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
        //...
        
        private Entry[] table;//Entry数组
        
        //set方法
        private void set(ThreadLocal<?> key, Object value) {
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                if (k == key) {
                    e.value = value;
                    return;
                }
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
        //get方法
        private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }
    }
    

    HashMap不同的是,

    1. 他继承了WeakReferncekey必须是ThreadLocalvalue是Object,即任意类型,并且在构造函数中将key传入作为弱引用构造函数的参数。
    2. Entry并没有引用一个next之类的指针,因此无法构成HashMap那样的链表。
    3. 纯粹的是维护一个Entry数组。

    继承WeakReferenc是因为:ThreadLocal作为key,如果是强引用,会一直被这个ThreadLocalMap引用,而只要后者对应的线程没有结束,那么就算在别处因为不需要了,而将该ThreadLoacal释放(=null),由于在map中的强引用,ThreadLocal对象也无法回收。

    因此这里只要设计成弱引用,在别处释放后,垃圾收集器就可以顺利回收ThreadLocal对象。

    ThreadLocal

    ThreadLocal对象实质上是做为一个key,在不同的线程中的map里,存取不同的对象。

    public ThreadLocal() {
        //...
        
        public T get() {
            Thread t = Thread.currentThread();//获取当前线程
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);//当前对象作为key去getEntry(this)
                if (e != null) {
                    @SuppressWarnings("unchecked")
                    T result = (T)e.value;
                    return result;
                }
            }
            return setInitialValue();
        }
        
        public void set(T value) {
            Thread t = Thread.currentThread();//获取当前线程
            ThreadLocalMap map = getMap(t);
            if (map != null)
                map.set(this, value);//当前对象作为key去set(this,value)
            else
                createMap(t, value);
        }
    }
    

    剩下的就是一些实现细节了,直接到源码里面去看就行了,主要还是看看顶部的工作原理图,理解原理就行。

    相关文章

      网友评论

          本文标题:ThreadLocal

          本文链接:https://www.haomeiwen.com/subject/fplnbftx.html