Java併發-深入理解ThreadLocal
阿新 • • 發佈:2018-11-21
一、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。