原文:https://cloud.tencent.com/developer/article/1333298

 

聊聊JDK源码中ThreadLocal的实现

主要方法:

  • ThreadLocal的get方法 ThreadLocal之get流程: 1、获取当前线程t; 2、返回当前线程t的成员变量ThreadLocalMap(以下简写map); 3、map不为null,则获取以当前线程为key的ThreadLocalMap的Entry(以下简写e),如果e不为null,则直接返回该Entry的value; 4、如果map为null或者e为null,返回setInitialValue()的值。setInitialValue()调用重写的initialValue()返回新值(如果没有重写initialValue将返回默认值null),并将新值存入当前线程的ThreadLocalMap(如果当前线程没有ThreadLocalMap,会先创建一个)。
public T get() {
     Thread t = Thread.currentThread();
     ThreadLocalMap map = getMap(t);
     if (map != null) {
         ThreadLocalMap.Entry e = map.getEntry(this);
         if (e != null) {
             @SuppressWarnings("unchecked")
             T result = (T)e.value;
             return result;
         }
     }
     return setInitialValue();
 }
  • ThreadLocal的set方法 ThreadLocal之set流程: 1、获取当前线程t; 2、返回当前线程t的成员变量ThreadLocalMap(以下简写map); 3、map不为null,则更新以当前线程为key的ThreadLocalMap,否则创建一个ThreadLocalMap,其中当前线程t为key;
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}

ThreadLocal主要的代码实现

下面代码时楼主认为ThreadLocal中比较重要的,还是比较容易看懂的,就不在一一细说

public class ThreadLocal<T> {
    /**
     * ThreadLocals依赖于附加的每线程线性探测哈希映射到每个线程(Thread.threadLocals和 
     * inheritableThreadLocals)。 ThreadLocal对象充当键,通过threadLocalHashCode搜索。 这是一个自定义哈希码
     * (仅在ThreadLocalMaps内有用),可以消除哈希冲突
     * 在连续构造ThreadLocals的常见情况下
     * 由相同的线程使用,同时保持良好的行为和异常情况的发生。
     */
    private final int threadLocalHashCode = nextHashCode();

    /**
     * 下一个哈希码将被发出,原子更新,从零开始。
     */
    private static AtomicInteger nextHashCode =
        new AtomicInteger();

    /**
     * 连续生成的散列码之间的区别 , 将隐式顺序线程本地ID转换为近乎最佳的散布
     * 两倍大小的表的乘法散列值。
     */
    private static final int HASH_INCREMENT = 0x61c88647;

    /**
     * Returns the next hash code.
     */
    private static int nextHashCode() {
        return nextHashCode.getAndAdd(HASH_INCREMENT);
    }

    /**
     * 返回此线程局部变量的当前线程的“初始值”。 在线程首次访问带有{@link #get}方法的变量时,将调用此方法,
     * 除非线程先前调用了{@link #set}方法,在这种情况下,initialValue方法不会 为该线程调用。 
     * 通常,每个线程最多调用一次此方法,但在后续调用{@link #remove}后跟{@link #get}时可能会再次调用此方法。 
     * <p>这个实现只是返回{@code null}; 如果程序员希望线程局部变量的初始值不是{@code null},
     * 则必须对子代码{@CodeLocal}进行子类化,并重写此方法。 通常,将使用匿名内部类。
     */
    protected T initialValue() {
        return null;
    }

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    /**
     * SuppliedThreadLocal是JDK8新增的内部类,只是扩展了ThreadLocal的初始化值的方法而已
     * ,允许使用JDK8新增的Lambda表达式赋值。需要注意的是,函数式接口Supplier不允许为null。
     */
    static final class SuppliedThreadLocal<T> extends ThreadLocal<T> {

        private final Supplier<? extends T> supplier;

        SuppliedThreadLocal(Supplier<? extends T> supplier) {
            this.supplier = Objects.requireNonNull(supplier);
        }

        @Override
        protected T initialValue() {
            return supplier.get();
        }
    }

    /**
     * ThreadLocalMap是定制的hashMap,关于HashMap的更详细的问题请参看《聊聊HashMap源码》,
     * 仅用于维护当前线程的本地变量值。仅ThreadLocal类对其有操作权限,
     * 是Thread的私有属性。为避免占用空间较大或生命周期较长的数据常驻于内存引发一系列问题,
     * hash table的key是弱引用WeakReferences。当空间不足时,会清理未被引用的entry。
     */
    static class ThreadLocalMap {

        static class Entry extends WeakReference<ThreadLocal

相关文章: