ThreadLocal

這個東東大家可能平時會聽說過,但是了解可能不是很多,當然網上也有了很多介紹文章,這里我只按照我的理解來說一下。知道這個東西應該挺多都是看 Looper 看到的。
我們先看看這個東西都是怎么用的:

private final Handler uiThreadHandler = new Handler(Looper.getMainLooper());
ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
int mainThreadNum = 1;int workerThreadNum = 2;
public void testThreadLocal() {
    threadLocal.set(mainThreadNum);
    new Thread(new Runnable() {
        @Override
        public void run() {
            threadLocal.set(workerThreadNum);
            uiThreadHandler.post(new Runnable() {
                @Override
                public void run() {
                    Log.d("UIThread", "" + threadLocal.get());
                }
            });
            Log.d("WorkerThread", "" + threadLocal.get());
        }
    }).start();
    Log.d("UIThread", "" + threadLocal.get());
}

這里的輸出

UIThread: 1
WorkerThread: 2
UIThread: 1

可見,ThreadLocal 的功能就是在不同 Thread set 進去的數據不會相互干擾并且可以直接獲取到。

然后我們說一下這個東西是怎么實現的:

public class ThreadLocal<T> {
    private final int threadLocalHashCode = nextHashCode();
    private static AtomicInteger nextHashCode = new AtomicInteger();
    public ThreadLocal() {  }
    ...
    static class ThreadLocalMap {
        ...
    }
}

不管別的,先看構造函數與成員變量。由上可知,可以隨意構造實例,并且成員變量只有一個 threadLocalHashCode,所以很明顯的可以知道這貨就是個皮包公司,它并不存儲任何實例,只是包含了一個這個實例的索引,也就是threadLocalHashCode

那接下來我們在看看它的成員函數,這里只那 set 來舉例:

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

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

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

這里我們可能就比較清晰為什么 ThreadLocal 可以提供這種可以在不同線程存入/讀取數據而互不干擾的功能了。
就是因為實際的變量并不是存入到了 ThreadLocal 中,而是存入到了這個操作對應的 Thread.threadLocals 中了(可以看上邊的 getMap 函數)。而且這個 Thread.threadLocals 的實例化也是在 ThreadLocal 的代碼中(createMap 函數)。

這個變量在 Thread 中的定義:

public class Thread implements Runnable {
    ...
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

就是一個引用而已,那現在就指向了 ThreadLocalMap 這個數據結構。

static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal> {
    Object value;
    Entry(ThreadLocal k, Object v) {
        super(k);
        value = v;
    }
}

private static final int INITIAL_CAPACITY = 16;
private Entry[] table;ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {

    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    ...
}}

這里邊最主要的其實就是這個數組 Entry[] table,這個 Entry 的定義也在上邊了,其實就是一個包含了具體變量的 ThreadLocal 的弱引用。
而 threadLocalHashCode 這個變量就是計算具體變量在這個數組中的索引的。

ok,整個的東西已經串下來了。

當然,這里邊疑問還有很多,比如 threadLocalHashCode 這個具體的計算方式,這個 table 數組是如何擴容等問題,大家可以自行看代碼了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容