DIY主題討論12:ThreadLocal的問題根源
ThreadLocal理解
- ThreadLocal意義:實現對象在線程內的透傳,可以跨類跨方法傳遞數據
- ThreadLocal變量的定義:
ThreadLocal變量必須定義爲static,非static的threadLocal也就失去了跨類跨方法傳遞數據的能力。
private static final ThreadLocal<T> threadLocal=new ThreadLocal<>();
- ThreadLocal值存儲位置:
ThreadLocal類內部有ThreadLocalMap靜態內部類,ThreadLocalMap還有一個靜態內部類Entity,ThreadLocal的值實際上存儲在ThreadLocalMap的Entity中。但是ThreadLocalMap是線程Thread的成員變量,也就是說ThreadLocal的值實際上是存在Thread對象中。
問題1:ThreadLocal如何回收value,什麼時候回收?
因爲ThreadLocal使用的時候,ThreadLocal對象要被設置爲static類型,也就是不會隨着線程的銷燬而銷燬。
進一步理解ThreadLocalMap的Entity,Entity繼承自WeakReference,Entity便具有弱引用的特性,爲何使用弱引用,原意是希望ThreadLocal對象消失時,線程對象持有的這個ThreadLocal不再有意義,應該隨着GC回收。Entity是鍵值對形式,key是ThreadLocal對象,value是實際的值,但是ThreadLocal對象是static類型,因此即使在線程銷燬後,entity的key引用ThreadLocal對象,因爲ThreadLocal對象一直存在導致entity不能被回收,造成內存泄漏。
正確用法:在ThreadLocal的value使用完後,調用ThreadLocal對象的remove方法,顯式移除,回收value。
問題2:ThreadLocal爲什麼會產生髒數據?
ThreadLocal產生髒數據主要發生在線程複用的場景下,也就是在使用線程池複用線程時要注意髒數據問題。
髒數據產生的原因:ThreadLocal的變量實際是存儲在ThreadLocalMap中,而ThreadLocalMap是線程Thread的成員變量,因此當一個線程被線程池複用,ThreadLocalMap也會被複用,這時如果上一個線程使用時候的ThreadLocalMap值沒有被清除,就會產生髒數據。