ThreadLocal源码解析

Posted 读书使人进步

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ThreadLocal源码解析相关的知识,希望对你有一定的参考价值。

主要用途

  1)设计线程安全的类

  2)存储无需共享的线程信息

设计思路

ThreadLocalMap原理

1)对象存储位置-->当前线程的ThreadLocalMap

  ThreadLocalMap是在ThreadLocal中定义的静态内部类,用于存放线程的信息,以ThreadLocal或InheritableThreadLocal为key,对象为value.每个Thread都有两个ThreadLocalMap,如下

    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
   //存放线程自己的信息,注册ThreadLocal
    ThreadLocal.ThreadLocalMap threadLocals = null;

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.  
     */ 
     //父线程信息的拷贝,注册InheritableThreadLocal
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

  2)ThreadLocalMap,实现自定义Map,实现存储的大致原理如下

        /**
         * The entries in this hash map extend WeakReference, using
         * its main ref field as the key (which is always a
         * ThreadLocal object).  Note that null keys (i.e. entry.get()
         * == null) mean that the key is no longer referenced, so the
         * entry can be expunged from table.  Such entries are referred to
         * as "stale entries" in the code that follows.
         */
     //封装ThreadLocal和对象
        static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;
            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
        }
        /**
         * The table, resized as necessary.
         * table.length MUST always be a power of two.
         */
     //数组存放entry
        private Entry[] table;
        private Entry getEntry(ThreadLocal key) {
        //利用ThreadLocal的哈希值属性定位在table中的位置
            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);
        }

ThreadLocal原理

    /**
     * Returns the value in the current thread\'s copy of this
     * thread-local variable.  If the variable has no value for the
     * current thread, it is first initialized to the value returned
     * by an invocation of the {@link #initialValue} method.
     *
     * @return the current thread\'s value of this thread-local
     */
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t); //获取当前线程的ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
    /**
     * 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); //key=ThreadLocal,value=对象
        else
            createMap(t, value);
    }
    /**
     * 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
    }
    protected T initialValue() { //初始化ThreadLocal时,预定义初始化value,默认为null
        return null;
    }
    /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    private T setInitialValue() {
        T value = initialValue(); //获取ThreadLocal初始化的value
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
    /**
     * 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
     * @param map the map to store.
     */
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue); //定义当前线程的 ThreadLocal.ThreadLocalMap threadLocals
    }

  注意,在new ThreadLocal时可以通过T java.lang.ThreadLocal.initialValue()定义存储的初始化对象

InheritableThreadLocal原理

  主要实现

  1)覆盖ThreadLocal的方法,将存储位置定位到ThreadLocal.ThreadLocalMap inheritableThreadLocals

  2)在从父线程获取inheritableThreadLocals,通过childValue定制复制的行为.

  源码如下

public class InheritableThreadLocal<T> extends ThreadLocal<T> { //ThreadLocal的子类
    /**
     * Computes the child\'s initial value for this inheritable thread-local
     * variable as a function of the parent\'s value at the time the child
     * thread is created.  This method is called from within the parent
     * thread before the child is started.
     * <p>
     * This method merely returns its input argument, and should be overridden
     * if a different behavior is desired.
     *
     * @param parentValue the parent thread\'s value
     * @return the child thread\'s initial value
     */
    protected T childValue(T parentValue) {
        return parentValue;   //在ThreadLocalMap(ThreadLocalMap parentMap)时,定制复制行为
    }
    /**
     * Get the map associated with a ThreadLocal. 
     *
     * @param t the current thread
     */
    ThreadLocalMap getMap(Thread t) {    
       return t.inheritableThreadLocals;  //重定向到线程的对应位置
    }
    /**
     * Create the map associated with a ThreadLocal. 
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the table.
     * @param map the map to store.
     */
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);   //重定向到线程的对应位置
    }
}

以上是关于ThreadLocal源码解析的主要内容,如果未能解决你的问题,请参考以下文章

ThreadLocal源码解析

JDK1.8中ThreadLocal源码解析

JDK1.8中ThreadLocal源码解析

Java 8 ThreadLocal 源码解析

ThreadLocal源码解析

ThreadLocal源码解析