Understanding ThreadLocal And InheritableThreadLocal

Use ThreadLocal Example

// create static global reference s1(type: ThreadLocal)
public static ThreadLocal<String> s1 = new ThreadLocal<String>();

// then set value in thread (just which thread run it)
s1.set("value");

//  then you can get the value where the thread is running 
s1.get();

//在線程池環境中須要手動移除它,(線程終止會自動移除ThreadLocal,但線程池的線程還會繼續使用)
s1.remove()

The Magic of ThreadLocal

只有一個靜態引用(s1),可是卻能夠在不一樣的線程中取到不一樣的值,why?git

先看一下 set 方法github

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);  //從這裏能夠看出 每一個線程對應一個 ThreadLocalMap 
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

// 先來看初次賦值
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue); // threadLocals 線程的內部變量
    }

// ThreadLocalMap 的構造方法
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);
        }
  1. 每一個線程對應一個 ThreadLocalMap
  2. ThreadLocalMap的key 的值就是 ThreadLocal 自己(s1),value 就是 set 傳入的值

咱們再來看一下 get 方法異步

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);  //取出(s1)對應的值
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

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

get 方法就是簡單的取值ide

Deep In TheadLocal (weakReference and weakHashMap)

咱們從上面知道 ThreadLocalMap 是線程存儲ThreadLocal的地方,它相似於WeakHashMap:this

/**
         * 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.
         */
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

上面咱們看到,entry 的key 存儲的是ThreadLocal (s1)的應用,可是這個引用是個弱引用:線程

key -------(弱引用)----->> ThreadLocal Instance <<------強引用 -------s1code

因此若是 s1=null,那麼 ThreadLocal Instance 是會被回收的進程

so why we should use WeakReference?ci

InheritableThreadLocal

做用就是在子進程中能夠取到父進程的ThreadLocal的值。rem

/*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

InheritableThreadLocal 也只是存儲在 ThreadLocalMap 裏的

InheritableThreadLocal which subclasses ThreadLocal class is used in such situations. This class has only one method 'protected Object childValue(Object parentValue)' which is used to set the initial value of the InheritableThreadLocal variable in the child thread as a function of a ThreadLocal variable (passed as a parameter) in the parent thread. This method is called from within the parent thread before the child thread is created and the default implementation will make the child values identical to parent's, but we can override the childValue() method to set the child value as a function of the parent value for those ThreadLocals which have values in the parent thread. By default the childValue() returns the same input argument, but again an override of the childValue method might change this behavior as well.

惟一的疑問就是何時給子線程的inheritableThreadLocals 變量賦的值,就是在父進程建立子進程的時候 調用的 childValue(Object parentValue) 方法。

More

思考:涉及到線程池 和異步操做的時候要怎麼傳遞ThreadLocal?

參考:Transmittable ThreadLocal(TTL)

相關文章
相關標籤/搜索