如上圖所示html
每一個Thread 都有一個map,裏面存着Entry<Key,value>,而key
是實現了WeakReference
的ThreadLocal
,若是不是WeakReference
,那麼可能Entry裏面的key和value在線程結束纔會進行GC,可是因爲是WeakReference
,所以當Key被設置爲null
時,key就會被 gc 回收.spa
可是因爲value
還在currentThread
->Map
->Entry
->value
中,所以致使了內存泄漏線程
hreadLocalMap類的設計自己已經有了這一問題的解決方案,那就是在每次get()
/set()
/remove()
ThreadLocalMap中的值的時候,會自動清理key爲null的value。如此一來,value也能被回收了。設計
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; }
中的code
if (k == null) expungeStaleEntry(i);
expungeStaleEntry保證了key爲null的狀況下value也置爲nullhtm
private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; // expunge entry at staleSlot tab[staleSlot].value = null; tab[staleSlot] = null; size--; // Rehash until we encounter null Entry e; int i; for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get(); if (k == null) { e.value = null; tab[i] = null; size--; } else { int h = k.threadLocalHashCode & (len - 1); if (h != i) { tab[i] = null; // Unlike Knuth 6.4 Algorithm R, we must scan until // null because multiple entries could have been stale. while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } } return i; }
原文出處:https://www.cnblogs.com/Draymonder/p/10433516.htmlblog