【Android】ThreadLocal源碼閱讀

在查看Handler源碼的時候可以看到其必須綁定一個Looper,然後通過Looper.prepare()方法獲取,而這個Looper對象則是保存在ThreadLocal中的。

定義

ThreadLocal在官網的描述是實現每個線程獨立的變量,所有線程共享一個ThreadLocal對象,當一個線程的值改變時不會影響其他線程的值。

源碼

1. set
獲取當前線程的ThreadLocalMap實例對象,已經有了就直接把值value設置進去,沒有的話創建並設置值

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

創建並設置value

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

查看ThreadLocalMap構造函數可以知道它創建了一個容量是16的Entry數組,並通過位運算獲取到下標i,將值保存到數組中

        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);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

Entry是一個繼承弱引用WeakReference的類,這是爲了Thread不存活時方便垃圾回收

        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;

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

2. get
get源碼邏輯也差不多,如果存在相應的ThreadLocalMap並且獲取到的Entry不爲null就從中取值

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

否則就創建一個null對象走一下set方法並返回null

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

初始化一個null

    protected T initialValue() {
        return null;
    }

ThreadLocalMap獲取對象的方法就是先獲取下標再獲取對應數據

        private Entry getEntry(ThreadLocal<?> key) {
            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);
        }

當對應下標下數據爲null或者ThreadLocal不相同時座標向後移動查找對象

        private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
            Entry[] tab = table;
            int len = tab.length;

            while (e != null) {
                ThreadLocal<?> k = e.get();
                if (k == key)
                    return e;
                if (k == null)
                    expungeStaleEntry(i);
                else
                    i = nextIndex(i, len);
                e = tab[i];
            }
            return null;
        }

總結

ThreadLocal實現每個線程的局部變量存儲,並且支持null值的保存,方便每個線程處理自己的狀態並且不影響其他線程。

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