ThreadLocal使用和原理
實現機制
1、每個Thread對象內部都維護了一個ThreadLocalMap這樣一個ThreadLocal的Map,可以存放若干個ThreadLocal。
/* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;2、當我們在調用get()方法的時候,先獲取當前線程,然后獲取到當前線程的ThreadLocalMap對象,如果非空,那么取出ThreadLocal的value,否則進行初始化,初始化就是將initialValue的值set到ThreadLocal中。
public T get() {//獲取當前線程Thread t = Thread.currentThread();//每個線程擁有一個map,取出來的是線程t的ThreadLocal.ThreadLocalMap對象ThreadLocalMap map = getMap(t); if (map != null) {//this->ThreadLocal實例是作為map的key來使用的ThreadLocalMap.Entry e = map.getEntry(this);if (e != null)return (T)e.value;}//初始化這個線程的ThreadLocalMap,并且返回nullreturn setInitialValue();} private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;}protected T initialValue() {return null;}
3、當我們調用set()方法的時候,很常規(guī),就是將值設置進ThreadLocal中。
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)//一個thread.ThreadLocalMap 可以維護多個不同ThreadLocal的值map.set(this, value);elsecreateMap(t, value);}事實上,從本質來講,就是每個線程都維護了一個map,而這個map的key就是threadLocal,而值就是我們set的那個值,每次線程在get的時候,都從自己線程的變量map中以ThreadLocal為key來取值,總體來講,ThreadLocal這個變量的狀態(tài)根本沒有發(fā)生變化,他僅僅是充當一個key的角色,另外提供給每一個線程一個初始值。
內存泄露
ThreadLocalMap使用ThreadLocal的弱引用作為key,如果一個ThreadLocal沒有外部強引用來引用它,那么系統(tǒng) GC 的時候,這個ThreadLocal勢必會被回收,ThreadLocalMap中就會出現key為null的Entry,就沒有辦法訪問這些key為null的Entry的value,如果當前線程再遲遲不結束的話,這些key為null的Entry的value就會一直存在一條強引用鏈:Thread Ref -> Thread -> ThreaLocalMap -> Entry -> value永遠無法回收,造成內存泄漏。
ThreadLocalMap的設計中已經考慮到這種情況,也加上了一些防護措施:在ThreadLocal的get(),set(),remove()的時候都會清除線程ThreadLocalMap里所有key為null的value。
為什么用弱引用?
key 使用強引用:引用的ThreadLocal的對象被回收了,但是ThreadLocalMap還持有ThreadLocal的強引用,如果沒有手動刪除,ThreadLocal不會被回收,導致Entry內存泄漏。
key 使用弱引用:引用的ThreadLocal的對象被回收了,由于ThreadLocalMap持有ThreadLocal的弱引用,即使沒有手動刪除,ThreadLocal也會被回收。value在下一次ThreadLocalMap調用set,get,remove的時候會被清除,否則value內存溢出。
由于ThreadLocalMap的生命周期跟Thread一樣長,如果沒有手動刪除對應key,都會導致內存泄漏,但是使用弱引用可以多一層保障:弱引用ThreadLocal不會內存泄漏,對應的value在下一次ThreadLocalMap調用set,get,remove的時候會被清除。
使用舉例
public class TestThreadLocal {private static int j = 0;public static void main(String[] args) {final ThreadLocal<String> tl1 = new ThreadLocal<String>();final ThreadLocal<String> tl2 = new ThreadLocal<String>();ExecutorService es = Executors.newFixedThreadPool(10);for (int i = 0; i < 30; i++) {es.execute(new Runnable() {@Overridepublic void run() {synchronized (TestThreadLocal.class) {tl1.set("tl1"+"-"+j);tl2.set("tl2"+"-"+j);System.out.println("當前線程" + Thread.currentThread()+"-"+ j + "放入data=" + tl1.get());System.out.println("當前線程" + Thread.currentThread()+"-"+ j + "放入data=" + tl2.get());j++;}try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("當前線程" + Thread.currentThread() + ":取出data=" + tl1.get());System.out.println("當前線程" + Thread.currentThread() + ":取出data=" + tl2.get());}});}} }?
轉載于:https://www.cnblogs.com/wade-luffy/p/5755481.html
總結
以上是生活随笔為你收集整理的ThreadLocal使用和原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android Studio项目结构
- 下一篇: p4 是否能自动merge