學 無 止 境 , 與 君 共 勉 。java
ThreadLocal
是一個線程內部的變量,只在本線程中使用,隔離其餘線程ThreadLocal
內部維護了一個ThreadLocalMap
Thread
內部引用了ThreadLocalMap
ThreadLocalMap
能夠保存
鍵值對,可是一個ThreadLocal
只能保存一個值,而且各個線程數據互不干擾ThreadLocalMap
存儲時的key
永遠爲當前的ThreadLocal
ThreadLocalMap
存儲時的key
是弱引用的每一個ThreadLocal
只能存儲一個數據,若是須要存儲多個值的話,能夠定義多個ThreadLocal
。ThreadLocal
在內部維護了一個ThreadLocalMap
用來存儲這些值。web
ThreadLocalMap
並無去實現Map
接口,它定義了一個Entry
數組,每一個Entry
以<key,value>
的形式來保存值,其中key
爲當前ThreadLocal
自己,value
爲要保存的值。數組
注意
Entry
繼承了WeakReference
,它的key
是弱引用的,會被垃圾回收掉,因此會存在key
爲null
的狀況安全
ThreadLocalMap
提供了三個方法:微信
ThreadLocal
爲key
存放值ThreadLocal
爲key
獲取存放的值Thread.currentThread()
ThreadLocalMap
ThreadLocalMap
是否存在createMap
,初始化一個ThreadLocalMap
,並賦值ThreadLocal
做爲key
,進行插入操做:
Thread.currentThread()
ThreadLocalMap
ThreadLocalMap
是否存在setInitialValue
進行初始化,並返回null
;ThreadLocal
做爲key
獲取值:
清理當前ThreadLocal
對應的Entry
對象。並調用清理重置方法。app
ThreadLocalMap
並無實現Map
接口,它不是經過鏈表的形式去避免Hash衝突的,而是經過後移的方式去實現。set方法時,若是當前要存放的位置的key
和要設置的key
不一致,則會對下一個位置進行判斷,直到找到key
相同或者爲null
或者Entry
爲null
的位置。工具
在實際的項目中,咱們的線程通常都是由線程池來管理的,線程會一直存在,ThreadLocalMap
的value就有可能得不到回收,發送內存泄漏。爲了處理這一問題,ThreadLocal
的get()、set()方法都有可能會清除key
爲null
的Entry
對象。安全起見,當咱們使用完後應該手動調用remove()
方法清理掉數據。spa
某些數據好比用戶ID,極可能在整條業務線上多個方法中都須要用到,若是經過方法參數的形式一層一層的傳遞下去,總體代碼顯得凌亂不優雅,這時能夠經過ThreadLocal
的方式存儲。一般能夠經過AOP或者攔截器的方式進行賦值,執行完業務邏輯以後調用remove()
方法。線程
private final static ThreadLocal<UserInfo> TL_USER = new ThreadLocal<>();
TL_USER.set(userInfo);
UserInfo userInfo = TL_USER.get();
TL_USER.remove();
複製代碼
在實際項目中咱們一般會將時間相關的方法寫在一個工具類中,每每會用到SimpleDateFormat
進行格式化,它是線程不安全的。能夠經過ThreadLocal來實現獨享對象code
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"));
複製代碼
創做不易,若是各位以爲有幫助,求點贊 支持
微信公衆號: 俞大仙