1. 程式人生 > 實用技巧 >Luogu6139 【模板】廣義字尾自動機(廣義 SAM)

Luogu6139 【模板】廣義字尾自動機(廣義 SAM)

ThreadLocal

map 和thread 關聯 map裡面的鍵是threadLocal 物件, value 是值

Thread ThreadLocalMap ThreaLocal 關係

  1. Thread內含ThreadLocalMap, 放入(this, value)
    ![](_assets/

用處

Spring的事務管理,用ThreadLocal儲存Connection,從而各個DAO可以獲取同一Connection,可以進行事務回滾,提交等操作。

  1. 先從對應執行緒上獲取對應的ThreadLocalMap 從ThreadLocalMap 中根據ThreadLocal 鍵值 設定值
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    // 1個執行緒對應一個 ThreadLocalMap
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    // 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);
    }

強引用、軟引用、弱引用和虛引用


    tab[i] = new Entry(key, value);
    static class ThreadLocalMap {

        /**
         * 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<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }

WeakReference對應用的物件userInfoLocal是弱引用,不會影響到userInfoLocal的GC行為。如果是強引用的話,線上程執行過程中,我們不再使用userInfoLocal了,將userInfoLocal置為null,但userInfoLocal線上程的ThreadLocalMap裡還有引用,導致其無法被GC回收(當然,可以等到執行緒執行結束後,整個Map都會被回收,但很多執行緒要執行很久,如果等到執行緒結束,便會一直佔著記憶體空間)。而Entry宣告為WeakReference,userInfoLocal置為null後,執行緒的threadLocalMap就不算強引用了,userInfoLocal就可以被GC回收了。map的後續操作中,也會逐漸把對應的"stale entry"清理出去,避免記憶體洩漏。
實際上只要ThreadLocal被定義成static的,那個WeakReference就是沒有用的。因為static欄位就是強引用,並且只要class load之後就永遠可達
那個WeakReference可能有用的時候是ThreadLocal不被定義為static的,它被作為引數在方法之間以及各執行緒之間傳遞。等到所有執行緒都不再能訪問到它了,GC會把它回收。但是此時map裡的那個entry還在,它包裹的物件是null了,那個value值也還在。它會在下一次expungeStaleEntry時被從map中清理掉。

ThreadLocalMap內部Entry中key使用的是對ThreadLocal物件的弱引用,這為避免記憶體洩露是一個進步,因為如果是強引用,那麼即使其他地方沒有對ThreadLocal物件的引用,ThreadLocalMap中的ThreadLocal物件還是不會被回收,而如果是弱引用則這時候ThreadLocal引用是會被回收掉的,雖然對於的value還是不能被回收,這時候ThreadLocalMap裡面就會存在key為null但是value不為null的entry項,雖然ThreadLocalMap提供了set,get,remove方法在一些時機下會對這些Entry項進行清理,但是這是不及時的,也不是每次都會執行的,所以一些情況下還是會發生記憶體洩露,所以在使用完畢後即使呼叫remove方法才是解決記憶體洩露的王道

為什麼使用完要清除:
使用的是執行緒池,建立的ThradeLocal 是作為Key 放線上程繫結的ThradLocalMap中的,不清除越來越對炸了