ThreadLocal概述:
ThreadLocal是一個本地線程副本變量工具類,運用到了線程封閉技術。
用來維護線程中的變量不被其他線程干擾而出現的一個結構,內部包含一個ThreadLocalMap類(該類由一個繼承自虛引用的Entry來存具體的值,需要留意還有一個用來存Entry的table數組),該類爲Thread類的一個實例屬性(非static的成員變量),該Entry存儲的key爲ThreadLocal對象自身,value爲我們要存儲的值或對象。
這樣一來,在不同線程中,持有的其實都是當前線程的變量副本,與其他線程完全隔離,以此來保證線程執行過程中不受其他線程的影響。
ThreadLocal使用流程:
使用時可以重寫initialValue()方法,當線程進行get調用時,獲取當前線程對象實例的threadLocals這個成員變量。
它的類型爲ThreadLocal.ThreadLocalMap,內部是一個繼承了WeakReference<ThreadLocal<?>>的Entry,可以存當前ThreadLocal引用和對應的值。
獲取之後進行一個是否爲null的判斷,Thread類中默認爲null,寫入或者更新通過initialValue()確定的值。
當線程需要取出線程本地變量的時候,還是從Thread實例對象中取出之前賦好值的threadLocals,再從ThreadLocalMap.Entry中取出實際對應的值。
因此ThreadLocal實際上是不存值的,只是起到存入或取出線程實例中ThreadLocalMap中線程對應值的功能。
只要線程處於活躍狀態(alive)並且ThreadLocal實例可以訪問,那麼每個線程都會持有着一個線程本地變量副本的隱式副本。
線程消失之後,線程本地實例的所有相關副本都會進行垃圾回收(除非存在對這些副本的其他引用)
注:因此雖然ThreadLocal它的底層存儲結構(ThreadLocalMap)是弱引用(Entry extends WeakReference<java.ThreadLocal<?>>),但是並不是這個弱引用的值一被置爲null就會被回收,因爲存活着的那個線程對它還有一個強引用 (ThreadLocal.ThreadLocalMap threadLocals = Entry(ThreadLocal<?> k, null);)
源代碼解析:ThreadLocal
內存泄露問題:
會引發內存泄露↓
通過調用remove()方法避免內存溢出
實際運用場景:
如果用SimpleDateFormat對象轉換日期格式,但是不想每次請求創建新的SimpleDateForma對象,爲了可以解決併發場景下的性能問題可以使用到ThreadLocal