InheritableThreadLocal:子線程繼承父線程的本地變量

歡迎關注本人公衆號

在這裏插入圖片描述

概述

ThreadLocal可以保存一些變量僅供當前線程使用,其他線程不可見。
實際工作中可能會由於任務複雜,父線程創建幾個子線程併發致性任務,那麼父線程的本地變量如何傳遞到子線程呢? 答案是使用InheritableThreadLocal。

代碼實例

public static ThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) throws Exception {
        threadLocal.set(12345);
        Thread thread = new MyThread();
        thread.start();
        System.out.println("main = " + threadLocal.get());
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("MyThread = " + threadLocal.get());
        }
    }

運行結果:

main = 12345
MyThread = 12345

子線程中獲取到了父線程的變量值。

如果將InheritableThreadLocal換爲ThreadLocal,則子線程打印結果爲MyThread = null,讀者自行驗證。

源碼分析

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
/**
* 重寫了childValue方法
* 父線程創建子線程時,向子線程複製InheritableThreadLocal變量時使用
*/
    protected T childValue(T parentValue) {
        return parentValue;
    }
    //注意這裏使用的是Thread對象裏的inheritableThreadLocals變量,而不是threadLocals
    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
    //將父線程的threadLocal變量拷貝到子線程
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

當我們在new Thread()時,會有從父線程拷貝線程本地變量到子線程的代碼:

public Thread() {
        this(null, null, "Thread-" + nextThreadNum(), 0);
    }
 public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        this(group, target, name, stackSize, null, true);
    }
private Thread(ThreadGroup g, Runnable target, String name,
                   long stackSize, AccessControlContext acc,
                   boolean inheritThreadLocals) {
        //省略...
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        //省略
    }    

默認情況下,inheritThreadLocals值爲true,parent.inheritableThreadLocals也不爲空,所以會執行ThreadLocal.createInheritedMap方法。

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
    return new ThreadLocalMap(parentMap);
}
private ThreadLocalMap(ThreadLocalMap parentMap) {
        Entry[] parentTable = parentMap.table;
        int len = parentTable.length;
        setThreshold(len);
        table = new Entry[len];

        for (Entry e : parentTable) {
            if (e != null) {
                @SuppressWarnings("unchecked")
                ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
                if (key != null) {
                    Object value = key.childValue(e.value);
                    Entry c = new Entry(key, value);
                    int h = key.threadLocalHashCode & (len - 1);
                    while (table[h] != null)
                        h = nextIndex(h, len);
                    table[h] = c;
                    size++;
                }
            }
        }
    }

這段代碼比較簡單,就是在創建子線程時逐個讀取父線程的本地變量,賦值給子線程本地變量。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章