Java中ThreadLocal的使用及原理詳解
簡介
ThreadLocal是JDK提供的,提供線程本地變量,主要用來存放線程獨有變量和解決參數(shù)傳遞問題的。
例子
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
可以看出,每個線程的變量是隔離開的,避免了出現(xiàn)線程不安全的問題,ThreadLocal是如何實現(xiàn)的呢?
原理
ThreadLocalMap
public class Thread implements Runnable {
ThreadLocal.ThreadLocalMap threadLocals = null;
}ThreadLocalMap是真正存儲數(shù)據(jù)的地方,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
//創(chuàng)建ThreadLocalMap,并將value存儲
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
//獲取線程的ThreadLocalMap
return t.threadLocals;
}
void createMap(Thread t, T firstValue) {
//創(chuàng)建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
//創(chuàng)建一個ThreadLocalMap,賦值為空
createMap(t, value);
return value;
}get方法是獲取當前線程的ThreadLocalMap,然后通過將ThreadLocal當做key,從ThreadLocalMap中獲取到相應的Entry,Entry里包含了key和value,最后將value返回,如果沒有key的值,就會調用setInitialValue方法,setInitialValue方法會初始化一個默認值,默認值是null,也可以重寫initialValue,獲得自己想要的默認值,如果沒有創(chuàng)建ThreadLocalMap,則創(chuàng)建,然后返回默認值
remove方法
public void remove() {
//獲取調用者線程自有的ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//刪除ThreadLocalMap中key為當前ThreadLocal的數(shù)據(jù)
m.remove(this);
}remove方法十分簡單,就是刪除ThreadLocalMap中key為當前ThreadLocal的數(shù)據(jù)
總結
通過看源碼,可以得出
- ThreadLcoal只是一個用來操作ThreadLocalMap的一個工具類和充當ThreadLocalMap的key。
- ThreadLocalMap是真正存儲數(shù)據(jù)的,但是ThreadLocalMap是存儲在每個線程中的。
- 每個線程都有各自的ThreadLocalMap,這也是實現(xiàn)線程隔離的根本原因。
到此這篇關于Java中ThreadLocal的使用及原理詳解的文章就介紹到這了,更多相關ThreadLocal的使用及原理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java中javamail發(fā)送帶附件的郵件實現(xiàn)方法
這篇文章主要介紹了java中javamail發(fā)送帶附件的郵件實現(xiàn)方法,較為詳細的分析了JavaMail發(fā)送郵件的用法,是非常實用的技巧,需要的朋友可以參考下2015-01-01
AsyncHttpClient?ChannelPool線程池頻道池源碼流程解析
這篇文章主要為大家介紹了AsyncHttpClient ChannelPool線程池頻道池源碼流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12

