美文网首页
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