ThreadLocal

概念

为每个线程提供独立的变量,线程间的变量互不冲突,不会产生安全问题。

实现

public void set(T value) {
    Thread t = Thread.currentThread();当前线程
    ThreadLocalMap map = getMap(t);取得线程的ThreadLocalMap对象
    if (map != null)
        map.set(this, value);存入数据,key为当前ThreadLocal
    else
        createMap(t, value);
}

public T get() {
    Thread t = Thread.currentThread();当前线程
    ThreadLocalMap map = getMap(t);取得线程的ThreadLocalMap对象
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);取出数据,key为当前ThreadLocal
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

再来看Thread中的定义
/* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

通过上面的注释就能看出个大概了,数据最终存在Thread中,它的ThreadLocalMap存放了不同ThreadLocal对应的值(KV)。

而ThreadLocalMap是ThreadLocal的内部静态类,定义如下:
image-20211102205523308

这个Map并没有实现Map接口,也是hash实现,内部有个private Entry[] table;
但这个Map的冲突解决机制只是简单地放到hash的下一个位置。

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal<?> k, Object v) {
        super(k);//代表对key是弱引用,它主要是关联没有内在联系的对象,在垃圾回收时如果没有强引用只有弱引用,就可以被回收。这里设置为弱引用是因为在取的时候只要计算传入k的hash就能获得位置得到Entry,然后可以获得object,跟key已经没有关系了,不如早点回收节省空间。
        value = v;
    }
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注