1. 程式人生 > 實用技巧 >ThreadLocal記憶體洩漏解析

ThreadLocal記憶體洩漏解析

ThreadLocal是什麼?來,百度百科

ThreadLocal是Thread的區域性變數,用於編多執行緒程式,對解決多執行緒程式的併發問題有一定的啟示作用。

ThreadLocal很容易讓人望文生義,想當然地認為是一個“本地執行緒”。其實,ThreadLocal並不是一個Thread,而是Thread的區域性變數,也許把它命名為ThreadLocalVariable更容易讓人理解一些。

就是一個當前執行緒私有的儲存一些當前執行緒內共享變數的一個東西。可以用來儲存使用者資訊(我這樣搞的,也不知道對不對)以及跨很多方法,在spring攔截器中通過解析JWT獲得使用者資訊,然後呼叫service查詢完整使用者,最後儲存到ThreadLocal中,在所有完成後再清除

好了,進入正題

先來段原始碼:

public class Thread implements Runnable {
 .......

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

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


可以看到在Thread類裡面有一個 ThreadLocal.ThreadLocalMap 型別的threadLocals一看是很多threadlocal嘛。這裡貼上馬士兵老師的圖
【圖不知道怎麼傳】
可以看到threadlocal的儲存方式,將自己作為key,儲存的值作為value放在map中,這裡再來看一下原始碼

static class Entry extends WeakReference<ThreadLocal<?>> {
    /** The value associated with this ThreadLocal. */
    Object value;
    Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
}

這裡的super(k)的意思是呼叫父類的建構函式,而父類是啥呢,顯而易見是WeakReference是弱引用,弱引用有個特點就是隻要發生垃圾回收,它所指向的物件就會被回收。那為啥threadlocal沒有被回收呢,其實還有個強引用指向他,這樣就保證了不會被回收,那為啥不把key也設定成強引用,但是呢,圖片上也說了,如過說將tl=null的話。這個物件會被回收嗎,顯然是不可能的,因為key也是強應用嘛,屬於gc root,肯定不可能被回收。但是外部又訪問不到,這不就造成記憶體洩漏了。所以說被設定為弱引用,但是這樣就不會發生記憶體洩露了嗎?

不是的,依然會發生,假設將tl=null,因為key是弱引用,所以只要發生垃圾回收就會被jvm回收,這樣的話value的值怎麼訪問?k都沒了還有v啥事,有人會說了,執行緒被回收了不就好了,是的。但是現在基本上都是使用執行緒池,執行緒還會被回收嗎。所以說,依然會發生記憶體洩漏,所以在使用完threadlocal後要記得呼叫remove方法移除。