ThreadLocal:多線程
爲解決多線程程序的併發問題提供了一種新的思路。使用這個工具類能夠很簡潔地編寫出優美的多線程程序。併發
當使用ThreadLocal維護變量時,ThreadLocal爲每一個使用該變量的線程提供獨立的變量副本,因此每個線程均可以獨立地改變本身的副本,而不會影響其它線程所對應的副本。jvm
從線程的角度看,目標變量就象是線程的本地變量,這也是類名中「Local」所要表達的意思。工具
ThreadLocal的接口方法 ThreadLocal類接口很簡單,只有4個方法,咱們先來了解一下: void set(Object value)設置當前線程的線程局部變量的值。 public Object get()該方法返回當前線程所對應的線程局部變量。 public void remove()將當前線程局部變量的值刪除,目的是爲了減小內存的佔用,該方法是JDK 5.0新增的方法。須要指出的是,當線程結束後,對應該線程的局部變量將自動被垃圾回收,因此顯式調用該方法清除線程的局部變量並非必須的操做,但它能夠加快內存回收的速度。 protected Object initialValue()返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是爲了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,而且僅執行1次。ThreadLocal中的缺省實現直接返回一個null。 值得一提的是,在JDK5.0中,ThreadLocal已經支持泛型,
該類的類名已經變爲ThreadLocal<T>。API方法也相應進行了調整,新版本的API方法分別是void set(T value)、T get()以及T initialValue()。 ThreadLocal是如何作到爲每個線程維護變量的副本的呢?
其實實現的思路很簡單:在ThreadLocal類中有一個Map,用於存儲每個線程的變量副本,Map中元素的鍵爲線程對象,而值對應線程的變量副本。
ThreadLocal源碼源碼的人都知道,ThreadLocal的設計的確巧妙,可是它也有一個缺陷:學習
可能會引發內存泄漏;優化
ThreadLocalMap中key維護着一個weakReference,它在下次GC以前會被清理,若是Value仍然保持着外部的強引用,該ThreadLocal沒有再進行set,get或者remove操做,時間長了就可能致使OutOfMemoryError ..net
lucene中的類CloseableThreadLocal對ThreadLocal作了處理,優化了其缺陷.學習一下:
當執行CloseableThreadLocal.set(T)時,內部其實只是把值賦給內部的ThreadLocal對象,即執行ThreadLocal.set(new WeakReference(T)),將T包裝成弱引用對象,目的就是當內存不足時,jvm能夠回收此對象.線程
這樣引入一個新的問題:當前線程還存活着的時候,由於內存不足而回收了弱引用對象,這樣會在下次調用get()時取不到值返回null,這是不可接受的.因此CloseableThreadLocal在內部還建立了一個私有的Map,WeakHashMap<Thread, T>,當線程只要存活時,則T就至少有一個引用存在,因此不會被提早回收。同時要注意另外一個問題,要對WeakHashMap的操做使用synchronized作同步.
文章轉載:https://blog.csdn.net/qunqunstyle99/article/details/94717256設計
線程池中的線程使用threadlocal會出現什麼問題?對象
線程池中的線程在任務執行完成後會被複用,因此在線程執行完成時,要對 ThreadLocal 進行清理(清除掉與本線程相關聯的 value 對象)。否則,被複用的線程去執行新的任務時會使用被上一個線程操做過的 value 對象,從而產生不符合預期的結果。