Java裏,每一個線程都有本身的ThreadLocalMap,裏邊存着本身私有的對象。Map的Entry裏,key爲ThreadLocal對象,value即爲私有對象T。在spring MVC中,經常使用ThreadLocal保存當前登錄用戶信息,這樣線程在任意地方均可以取到用戶信息了。spring
public class UserContext { private static final ThreadLocal<UserInfo> userInfoLocal = new ThreadLocal<UserInfo>(); public static UserInfo getUserInfo() { return userInfoLocal.get(); } public static void setUserInfo(UserInfo userInfo) { userInfoLocal.set(userInfo); } public static void clear() { userInfoLocal.remove(); } }
這裏,跳過ThreadLocal和ThreadLocalMap的工做原理及場景不講,主要來講說Entry爲何是WeakReference?多線程
/** * 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<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
先來看看WeakReference的做用,百度一下:函數
WeakReference是Java語言規範中爲了區別直接的對象引用(程序中經過構造函數聲明出來的對象引用)而定義的另一種引用關係。WeakReference標誌性的特色是:reference實例不會影響到被應用對象的GC回收行爲(即只要對象被除WeakReference對象以外全部的對象解除引用後,該對象即可以被GC回收),只不過在被對象回收以後,reference實例想得到被應用的對象時程序會返回null。
個人理解就是,WeakReference對應用的對象userInfoLocal是弱引用,不會影響到userInfoLocal的GC行爲。若是是強引用的話,在線程運行過程當中,咱們再也不使用userInfoLocal了,將userInfoLocal置爲null,但userInfoLocal在線程的ThreadLocalMap裏還有引用,致使其沒法被GC回收(固然,能夠等到線程運行結束後,整個Map都會被回收,但不少線程要運行好久,若是等到線程結束,便會一直佔着內存空間)。而Entry聲明爲WeakReference,userInfoLocal置爲null後,線程的threadLocalMap就不算強引用了,userInfoLocal就能夠被GC回收了。map的後續操做中,也會逐漸把對應的"stale entry"清理出去,避免內存泄漏。this
因此,咱們在使用完ThreadLocal變量時,儘可能用threadLocal.remove()來清除,避免threadLocal=null的操做。前者remove()會同時清除掉線程threadLocalMap裏的entry,算是完全清除;然後者雖然釋放掉了threadLocal,但線種threadLocalMap裏還有其"stale entry",後續還須要處理。spa