簡介
ThreadLocal是JDK提供的,提供執行緒本地變數,主要用來存放執行緒獨有變數和解決引數傳遞問題的,
例子
public static void main(String[] args) {
ThreadLocal threadLocal = new ThreadLocal();
for(int i=0;i<3;i++){
new Thread(()->{
double random = Math.floor(Math.random()*10);
threadLocal.set(random);
System.out.println("設定執行緒"+Thread.currentThread().getName()+",執行緒變數:"+random);
System.out.println("查看執行緒"+Thread.currentThread().getName()+",執行緒變數:"+threadLocal.get());
}).start();
}
}
設定執行緒Thread-2,執行緒變數:4.0
設定執行緒Thread-0,執行緒變數:9.0
設定執行緒Thread-1,執行緒變數:5.0
查看執行緒Thread-0,執行緒變數:9.0
查看執行緒Thread-2,執行緒變數:4.0
查看執行緒Thread-1,執行緒變數:5.0
可以看出,每個執行緒的變數是隔離開的,避免了出現執行緒不安全的問題,ThreadLocal是如何實作的呢?
原理
ThreadLocalMap
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
}
ThreadLocalMap是真正存盤資料的地方,ThreadLocalMap在各個執行緒中,為執行緒獨有的
set方法
public void set(T value) {
//獲取呼叫者執行緒
Thread t = Thread.currentThread();
//獲取呼叫者執行緒自有的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//如果map!=null直接設定值
map.set(this, value);
else
//創建ThreadLocalMap,并將value存盤
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
//獲取執行緒的ThreadLocalMap
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
//創建ThreadLocalMap,并設定firstValue
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
從set方法中第二行代碼ThreadLocalMap map = getMap(t);這段代碼是獲取當前執行緒的ThreadLocalMap,然后進行設定值,通過getMap方法可以看出,執行緒本地變數并不是存盤在ThreadLocal,而是存盤在各自執行緒的ThreadLocalMap threadLocals中的,ThreadLocal只是相當于一個工具類,對ThreadLocalMap進行操作而已,
get方法
public T get() {
//獲取呼叫者執行緒
Thread t = Thread.currentThread();
//獲取呼叫者執行緒自有的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
//獲取到當前ThreadLocal的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
private T setInitialValue() {
//獲取默認值(null),也可以重寫該方法
T value = initialValue();
//獲取呼叫者執行緒
Thread t = Thread.currentThread();
//獲取呼叫者執行緒自有的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//設定為空
map.set(this, value);
else
//創建一個ThreadLocalMap,賦值為空
createMap(t, value);
return value;
}
get方法是獲取當前執行緒的ThreadLocalMap,然后通過將ThreadLocal當做key,從ThreadLocalMap中獲取到相應的Entry,Entry里包含了key和value,最后將value回傳,如果沒有key的值,就會呼叫setInitialValue方法,setInitialValue方法會初始化一個默認值,默認值是null,也可以重寫initialValue,獲得自己想要的默認值,如果沒有創建ThreadLocalMap,則創建,然后回傳默認值
remove方法
public void remove() {
//獲取呼叫者執行緒自有的ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//洗掉ThreadLocalMap中key為當前ThreadLocal的資料
m.remove(this);
}
remove方法十分簡單,就是洗掉ThreadLocalMap中key為當前ThreadLocal的資料
總結
通過看原始碼,可以得出
- ThreadLcoal只是一個用來操作ThreadLocalMap的一個工具類和充當ThreadLocalMap的key,
- ThreadLocalMap是真正存盤資料的,但是ThreadLocalMap是存盤在每個執行緒中的,
- 每個執行緒都有各自的ThreadLocalMap,這也是實作執行緒隔離的根本原因,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/189953.html
標籤:其他
上一篇:SpirngBoot后臺使用QQ郵箱發送驗證碼實作全程序
下一篇:并發一(基本概念及理論準備)
