ThreadLocal、ThreadLocalMap、Thread的关系

1,923 阅读2分钟

  开门见山,直接先看ThreadLocal的类结构。

  ThreadLocal中定义了两个内部类,SuppliedThreadLocal不在讨论范围,还有一个就是ThreadLocal类了。
  能使用的方法有withInitial(Supplier<? extends S> supplier)、get()、set(T value)和remove()。
  接下来就通过set(T value)方法来解释ThreadLocal、ThreadLocalMap和Thread之间的关系。

set(T value)

    /**
     * Sets the current thread's copy of this thread-local variable
     * to the specified value.  Most subclasses will have no need to
     * override this method, relying solely on the {@link #initialValue}
     * method to set the values of thread-locals.
     *
     * @param value the value to be stored in the current thread's copy of
     *        this thread-local.
     */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

  首先是通过Thread的currentThread()获得了当前调用set(T value)方法的线程实例。

    /**
     * Returns a reference to the currently executing thread object.
     *
     * @return  the currently executing thread.
     */
    public static native Thread currentThread();

  接下来又调用了自己的getMap(Thread t)方法获得了ThreadLocalMap实例,这里很重要。   

    /**
     * Get the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param  t the current thread
     * @return the map
     */
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

  也就是说ThreadLocalMap实例是由每个Thread实例持有的。
  在拿到了Map后就是判空,先假设为空,也就是说当前Thread里的ThreadLocalMap实例为空。就会调用createMap(Thread t, T firstValue)方法。   

    /**
     * Create the map associated with a ThreadLocal. Overridden in
     * InheritableThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the map
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

  这里也很重要,可以看出ThreadLocal为Thread的threadLocals成员变量赋予了一个新的ThreadLocalMap实例。
  在实例化ThreadLocalMap时还往构造函数中传入了ThreadLocal自身的引用(this)和值(value)。   接下来再看看createMap(Thread t, T firstValue)方法中用到的ThreadLocalMap的构造函数。   

        /**
         * Construct a new map initially containing (firstKey, firstValue).
         * ThreadLocalMaps are constructed lazily, so we only create
         * one when we have at least one entry to put in it.
         */
        ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

  这里主要就是ThreadLocalMap自己的初始化,不难看出在Map中存放的key是ThreadLocal类型并不是Thread类型。
  

总结

  ThreadLocal自身不持有ThreadLocalMap实例,真正持有ThreadLocalMap实例的是Thread。
  ThreadLocal对ThreadLocalMap的操作是通过当前线程Thread实例获得ThreadLocalMap实例,然后再把自身当成key对map进行操作。

  1. 也就是说如果有多个ThreadLocal类去操作同一个线程,那么线程中的ThreadLocalMap就会有多个键值对。
  2. 而一个ThreadLocal类在一个线程中只能操作一个key-value。key就是自身,而value的类型可以是自己定义的对象实例。

废话

  这里说的比较简单,单纯按照自己的理解写的。还有很多的方法都没有去解释,但是举一反三还是很好理解的。有说的不对的地方还请多多指教。