欧美一区二区三区,国内熟女精品熟女A片视频小说,日本av网,小鲜肉男男GAY做受XXX网站

如何去理解ThreadLocal

老白2年前19瀏覽0評論

如何去理解ThreadLocal?

ThreadLocal是什么?

ThreadLocal是一個本地線程副本變量工具類。主要用于將私有線程和該線程存放的副本對象做一個映射,各個線程之間的變量互不干擾,在高并發場景下,可以實現無狀態的調用,特別適用于各個線程依賴不通的變量值完成操作的場景.

ThreadLocal特點:就是在一個線程里放一個數據,不管中間執行了什么操作。只要想獲取出來的時候,調用get就可以得到保存進去的數據.

ThreadLocal內部結構圖

從上面的結構圖中,我們可以看到ThreadLocal的核心機制

每個Thread 內部都有一個Map。Map里面存儲線程本地對象(key) 和線程的變量副本(value)。Thread 內部的Map是由 ThreadLocal為的,由ThreadLocal負責向map獲取和設置線程的變量值。

Thread線程內部的Map在類中描述如下:

ThreadLocal 為什么會內存泄漏

我們先分析一下ThreadLocalMap

我們可以知道每個Thread 維護一個 ThreadLocalMap,這個映射表的 key 是 ThreadLocal實例本身,value 是真正需要存儲的 Object,也就是說 ThreadLocal 本身并不存儲值,它只是作為一個 key 來讓線程從 ThreadLocalMap 獲取 value。仔細觀察ThreadLocalMap,這個map是使用 ThreadLocal 的弱引用作為 Key 的,弱引用的對象在 GC 時會被回收。

這樣,當把threadlocal變量置為null以后,沒有任何強引用指向threadlocal實例,所以threadlocal將會被gc回收。這樣一來,ThreadLocalMap中就會出現key為null的Entry,就沒有辦法訪問這些key為null的Entry的value,如果當前線程再遲遲不結束的話,這些key為null的Entry的value就會一直存在一條強引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value,而這塊value永遠不會被訪問到了,所以存在著內存泄露。

其實java 開發者,也考慮到了此問題,所以在get(),set()的時候,調用了expungeStaleEntry方法用來清除Entry中Key為null的Value,但是這是不及時的,也不是每次都會執行的,所以一些情況下還是會發生內存泄露。只有remove()方法中顯式調用了expungeStaleEntry方法。

下面看下ThreadLocal 的get()方法的實現:

下面繼續看 map.getEntry方法

當key 為null 時,調用getEntryAfterMiss方法

當key 為null 時,調用expungeStaleEntry 方法

也許有人會好奇,有上面方法,為什么還會導致內存泄漏呢?

一般我們設置的ThreadLocal設置為static的,static 變量可以作為GCRoot的根節點,所以會一直存在初始化了ThreadLocal, 調用set ,get 而沒有調用remove方法,所以會導致內存泄漏。

比如get方法,只有ThreadLocalMap中沒有所需要的key時,才會調用清除方法

內存泄漏的java代碼,如何去理解ThreadLocal