一、ThreadLocal是什麼?
ThreadLocal與線程同步機制不同,線程同步機制是多個線程共享同一個變量,而ThreadLocal是爲每一個線程創建一個單獨的變量副本,故而每個線程都可以獨立地改變自己所擁有的變量副本,而不會影響其他線程所對應的副本。可以說ThreadLocal爲多線程環境下變量問題提供了另外一種解決思路。
二、ThreadLocal常用方法的源碼
1、set()方法
//set操作,爲線程綁定變量
public void set(T value) {
Thread t = Thread.currentThread();//1.首先獲取當前線程對象
ThreadLocalMap map = getMap(t);//2.獲取該線程對象的ThreadLocalMap
if (map != null)
map.set(this, value);//如果map不爲空,執行set操作,以當前threadLocal對象爲key,實際存儲對象爲value進行set操作
else
createMap(t, value);//如果map爲空,則爲該線程創建ThreadLocalMap
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;//線程對象持有ThreadLocalMap的引用
}
//線程t.threadLocals定義
ThreadLocal.ThreadLocalMap threadLocals = null;
1. `ThreadLocal`僅僅是個變量訪問的入口;
2. 每一個`Thread對象`都有一個`ThreadLocalMap對象`;
2、get()方法
public T get() {
Thread t = Thread.currentThread();//1.首先獲取當前線程
ThreadLocalMap map = getMap(t);//2.獲取線程的map對象
if (map != null) {//3.如果map不爲空,以threadlocal實例爲key獲取到對應Entry,然後從Entry中取出對象即可。
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();//如果map爲空,也就是第一次沒有調用set直接get(或者調用過set,又調用了remove)時,爲其設定初始值
}
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;
}
//initialValue方法,默認是null,訪問權限是protected,即允許重寫。
protected T initialValue() {
return null;
}
三、使用示例
public class SeqCount {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
// 實現initialValue()
public Integer initialValue() {
return 0;
}
};
public int nextSeq(){
threadLocal.set(threadLocal.get() + 1);
return threadLocal.get();
}
public static void main(String[] args) {
SeqCount seqCount = new SeqCount();
//每個線程裏map的key都一樣(threadLocal實例爲同一個)
SeqThread thread1 = new SeqThread(seqCount);
SeqThread thread2 = new SeqThread(seqCount);
SeqThread thread3 = new SeqThread(seqCount);
SeqThread thread4 = new SeqThread(seqCount);
thread1.start();
thread2.start();
thread3.start();
thread4.start();
}
private static class SeqThread extends Thread {
private SeqCount seqCount;
SeqThread(SeqCount seqCount) {
this.seqCount = seqCount;
}
public void run() {
for(int i = 0 ; i < 3 ; i++){
System.out.println(Thread.currentThread().getName() + " seqCount :" + seqCount.nextSeq());
}
}
}
}
//執行結果
Thread-0 seqCount :1
Thread-0 seqCount :2
Thread-0 seqCount :3
Thread-2 seqCount :1
Thread-2 seqCount :2
Thread-2 seqCount :3
Thread-1 seqCount :1
Thread-1 seqCount :2
Thread-1 seqCount :3
Thread-3 seqCount :1
Thread-3 seqCount :2
Thread-3 seqCount :3
四、Thread、ThreadLocal、ThreadLocalMap關係圖
每個thread中都存在一個map,map的類型是
ThreadLocal.ThreadLocalMap
。Map中的key爲一個threadlocal實例(引用)。
五、應用場景
ThreadLocal在spring的事務管理,包括Hibernate的session管理等都有出現,在web開發中,有時會用來管理用戶會話 HttpSession,web交互中這種典型的一請求一線程的場景比較適合使用ThreadLocal。