Java中ThreadLocal的使用及原理詳解
簡介
ThreadLocal是JDK提供的,提供線程本地變量,主要用來存放線程獨(dú)有變量和解決參數(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("設(shè)置線程"+Thread.currentThread().getName()+",線程變量:"+random);
System.out.println("查看線程"+Thread.currentThread().getName()+",線程變量:"+threadLocal.get());
}).start();
}
}設(shè)置線程Thread-2,線程變量:4.0
設(shè)置線程Thread-0,線程變量:9.0
設(shè)置線程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在各個線程中,為線程獨(dú)有的
set方法
public void set(T value) {
//獲取調(diào)用者線程
Thread t = Thread.currentThread();
//獲取調(diào)用者線程自有的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//如果map!=null直接設(shè)置值
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,并設(shè)置firstValue
t.threadLocals = new ThreadLocalMap(this, firstValue);
}從set方法中第二行代碼ThreadLocalMap map = getMap(t);這段代碼是獲取當(dāng)前線程的ThreadLocalMap,然后進(jìn)行設(shè)置值,通過getMap方法可以看出,線程本地變量并不是存儲在ThreadLocal,而是存儲在各自線程的ThreadLocalMap threadLocals中的,ThreadLocal只是相當(dāng)于一個工具類,對ThreadLocalMap進(jìn)行操作而已。
get方法
public T get() {
//獲取調(diào)用者線程
Thread t = Thread.currentThread();
//獲取調(diào)用者線程自有的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
//獲取到當(dāng)前ThreadLocal的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
private T setInitialValue() {
//獲取默認(rèn)值(null),也可以重寫該方法
T value = initialValue();
//獲取調(diào)用者線程
Thread t = Thread.currentThread();
//獲取調(diào)用者線程自有的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//設(shè)置為空
map.set(this, value);
else
//創(chuàng)建一個ThreadLocalMap,賦值為空
createMap(t, value);
return value;
}get方法是獲取當(dāng)前線程的ThreadLocalMap,然后通過將ThreadLocal當(dāng)做key,從ThreadLocalMap中獲取到相應(yīng)的Entry,Entry里包含了key和value,最后將value返回,如果沒有key的值,就會調(diào)用setInitialValue方法,setInitialValue方法會初始化一個默認(rèn)值,默認(rèn)值是null,也可以重寫initialValue,獲得自己想要的默認(rèn)值,如果沒有創(chuàng)建ThreadLocalMap,則創(chuàng)建,然后返回默認(rèn)值
remove方法
public void remove() {
//獲取調(diào)用者線程自有的ThreadLocalMap
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//刪除ThreadLocalMap中key為當(dāng)前ThreadLocal的數(shù)據(jù)
m.remove(this);
}remove方法十分簡單,就是刪除ThreadLocalMap中key為當(dāng)前ThreadLocal的數(shù)據(jù)
總結(jié)
通過看源碼,可以得出
- ThreadLcoal只是一個用來操作ThreadLocalMap的一個工具類和充當(dāng)ThreadLocalMap的key。
- ThreadLocalMap是真正存儲數(shù)據(jù)的,但是ThreadLocalMap是存儲在每個線程中的。
- 每個線程都有各自的ThreadLocalMap,這也是實現(xiàn)線程隔離的根本原因。
到此這篇關(guān)于Java中ThreadLocal的使用及原理詳解的文章就介紹到這了,更多相關(guān)ThreadLocal的使用及原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java中javamail發(fā)送帶附件的郵件實現(xiàn)方法
這篇文章主要介紹了java中javamail發(fā)送帶附件的郵件實現(xiàn)方法,較為詳細(xì)的分析了JavaMail發(fā)送郵件的用法,是非常實用的技巧,需要的朋友可以參考下2015-01-01
SpringBoot如何進(jìn)行對象復(fù)制的實踐
本文主要介紹了SpringBoot 如何進(jìn)行對象復(fù)制,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容
這篇文章主要介紹了java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容的相關(guān)資料,需要的朋友可以參考下2017-04-04
AsyncHttpClient?ChannelPool線程池頻道池源碼流程解析
這篇文章主要為大家介紹了AsyncHttpClient ChannelPool線程池頻道池源碼流程解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
詳解Java?POI?excel自定義設(shè)置單元格格式
這篇文章主要介紹了Java?POI?excel設(shè)置單元格格式,自定義設(shè)置,設(shè)置單元格格式:來源_formats,更多數(shù)據(jù)類型從formats里面發(fā)現(xiàn),需要的朋友可以參考下2024-01-01

