java中threadlocal的理解
一、threadlocal的生命周期和ThreadLocalMap的生命周期
可以吧TreadLocal看做是一個map來使用,只不過這個map是指向當前線程中的threadLocals(ThreadLocalMap.class),這個threadLocals采用懶漢單例在一個線程中是唯一的。
Thread中的threadLocals屬性,存放的是當前線程在不同TreadLocal實例中的值ThreadLocalMap<TreadLocal,T>
1 public void set(T value) {
2 Thread t = Thread.currentThread();
3 ThreadLocalMap map = getMap(t);//return t.threadLocals;這里表示只有一個ThreadLocalMap副本
4 if (map != null)//采用懶漢模式
5 map.set(this, value);
6 else
7 createMap(t, value);//t.threadLocals = new ThreadLocalMap(this, firstValue);
8 }
可以通過查看當前線程中的threadLocals變量,來看當前線程持有多少個threadLocal,以及存的值。
ThreadLocalMap實例的生命周期隨着線程的結束而結束,因為ThreadLocalMap實例的唯一引用只存在當前線程中。ThreadLocal的生命周期,需要gc來決定,因為他的引用可能存在於多個線程中,此引用為弱引用。
弱引用的存在,導致可能內存泄露。當threadlocal=null,沒有任何強引用實例指向threadLocals中的key本來指向的threadlocal實例,gc回收threadlocal,導致val永遠不會被釋放。采用以下代碼來取代=null的操作,用remove函數來清除,threadLocals。
1 ThreadLocal local1 = new ThreadLocal();
2 local.remove();
二、ThreadLocal的作用
對於那些需要數據隔離,可以用ThreadLocal。
對於一個線程中的一個ThreadLocal只能存一個T類型的數據。(T為泛型)
ThreadLocal是線程安全的,所以可以用來封裝線程不安全的實例,不同線程之間新創建實例,保證線程安全。(另一種模式就是單例模式。)
三、示例
比較經典的例子就是github中的PageHelper中保存Page信息的時候使用了ThreadLocal。考慮到數據的同步,已經一個線程只會順序執行sql語句。
1 protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal();
2 protected static void setLocalPage(Page page) {
3 LOCAL_PAGE.set(page);
4 }
