ThreadLocal:java.lang.ThreadLocal
作用:解決多線程中數據共享的問題,即:解決了同一線程中隸屬於不同開發層次(表示層、業務層、持久層)的數據共享問題,故可以對執行邏輯和執行數據進行有效的解耦
應用:應用在同一個線程的不同開發層次中共享數據。例如:Struts2中的ActionContext、Spring中管理數據庫的連接、Hibernate中的Session
實現:
1)建立一個類,並在其中封裝一個靜態的ThreadLocal變量,使其成爲一個共享的數據環境。
2)在類中實現訪問靜態ThreadLocal變量的靜態方法(設值和取值)
【說明】:ThreadLocal通過操作當前線程中的一個內部變量(ThreadLocalMap)來達到與其它線程隔離的目的。
1)ThreadLocalMap變量屬於線程的內部屬性,不同的線程擁有完全不同的ThreadLocalMap變量
2)線程中的ThreadLocalMap變量的值是在ThreadLocal對象進行set或get操作時創建的,在創建之前會檢查當前線程中的ThreadLocalMap是否爲null,如果爲null則創建,如果不爲null,則使用已經存在的ThreadLocalMap
3)使用當前線程的ThreadLocalMap的關鍵在於:使用當前的ThreadLocal的實例作爲key進行儲存
【重要】:
1)一個ThreadLocal只能儲存一個變量,如果重複調用ThreadLocal的set方法,則新值會將舊值覆蓋。
2)如果需要在一個線程中共享多個變量,則可以將多個變量封裝到一個對象中,然後將該對象存儲在ThreadLocal中。Struts2中的ActionContext就是這樣設計的。
3)在ThreadLocalMap中,如果當前線程中定義了多個不同的ThreadLocal的實例,則它們會作爲不同的key進行儲存而不會相互干擾!
java.lang.Thread的部分源碼:
public class Thread implements Runnable {
//這裏省略了許多其它的代碼
ThreadLocal.ThreadLocalMap threadLocals = null;
}
java.lang.ThreadLocal的部分源碼:
public Class ThreadLocal<T> {
//這裏省略了許多其它的代碼
// 將value的值保存在當前線程的本地變量表(ThreadLocalMap)中
public void set(T value){
// 獲取當前線程
Thread t = Thread.currentThread();
// 調用getMap方法獲得當前線程中的本地變量表ThreadLocalMap
ThreadLocalMap map = getMap(t);
// 如果本地變量表ThreadLocalMap已經存在,則直接使用
if (map != null){
// 以當前的ThreadLocal的實例作爲key,儲存在當前線程中。ThreadLocalMap
// ThreadLocalMap中,如果當前線程中定義了多個不同的ThreadLocal的實例,則它們會作爲不同的key進行儲存而不會相互干擾
// ThreadLocalMap的set方法:private void set(ThreadLocal<?> key, Object value)
map.set(this, value);
} else {
// 如果ThreadLocalMap不存在,則初始化map
createMap(t, value);
}
}
// 獲取當前線程中以當前ThreadLocal實例爲key的變量值
public T get() {
// 獲取當前線程
Thread t = Thread.currentThread();
// 獲取當前線程中的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
// 獲取當前線程中以當前ThreadLocal實例爲key的變量值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
return (T)e.value;
}
}
// 當map不存在時,初始化map,並返回null
return setInitialValue();
}
// 從當前線程中獲取與之對應的ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
return t.threadlocals;
}
// 創建當前線程中的ThreadLocalMap
void createMap(Thread t, T firstValue) {
// 調用構造函數生成當前線程中的ThreadLocalMap
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
// 初始化當前線程的ThreadLocalMap
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
// 若當前線程的ThreadLocalMap不存在時,調用ThreadLocal的get()方法默認返回null。
// 若子類覆蓋父類ThreadLocal的該方法,則可以設置當(當前線程的)ThreadLocalMap不存在時,get()方法默認返回的值。
protected T initialValue() {
return null;
}
// ThreadLocalMap的定義
static class ThreadLocalMap{
// ...
}
}
應用舉例:Struts2中的ActionContext
ActionContext在內部封裝了一個靜態的ThreadLocal的實例,而這一實例操作的對象()又是ActionContext本身。
Struts2中的ActionContext的部分源碼:
public class ActionContext implements Serializable {
// 此處省略了很多代碼
// 封裝了一個ThreadLocal變量,儲存的內容是ActionContext本身
static ThreadLocal actionContext = new ThreadLocal();
// 在ThreadLocal中設置ActionContext,綁定到當前線程。
public static void setContext(ActionContext context){
actionContext.set(context);
// 注:ThreadLocal的set方法調用了ThreadLocalMap(當前線程的本地變量表)的set(threadLocal, value)方法:以當前的ThreadLocal的實例作爲key,儲存在當前線程的ThreadLocalMap屬性中
}
// 返回當前線程中儲存的ActionContext
public static ActionContext getContext(){
// 返回當前線程中儲存的ActionContext
return (ActionContext) actionContext.get();
}
}