java中ThreadLocal的簡(jiǎn)單理解

ThreadLocal

  • 從JDK1.2版本開始提供了ThreadLocal類,以一種新的思路解決多線程并發(fā)問題。使用ThreadLocal實(shí)例維護(hù)多線程變量時(shí),不會(huì)出現(xiàn)線程安全問題。雖然多個(gè)線程共用一個(gè)ThreadLocal實(shí)例,但在變量的使用上,各線程之間對(duì)變量不可見。

ThreadLocal的使用

ThreadLocal threadLocal = new ThreadLocal();

  • ThreadLocal提供無參的構(gòu)造函數(shù)進(jìn)行實(shí)例創(chuàng)建。在使用方面,該類也僅提供了幾個(gè)簡(jiǎn)單的方法進(jìn)行操作:

    1. set方法:threadLocal.set("threadLocal test")對(duì)ThreadLocal進(jìn)行值得設(shè)置。
    2. get方法:Object test = threadLocal.get()進(jìn)行值得獲取。
    3. remove方法:threadLocal.remove();刪除對(duì)應(yīng)線程中存儲(chǔ)的值。
  • 在JDK1.5版本開始,ThreadLocal提供泛型的支持,在獲取值時(shí)不再需要需要進(jìn)行類型強(qiáng)轉(zhuǎn)。

ThreadLocal<String> threadLocal = new ThreadLocal();
threadLocal.set("threadLocal test");
String test = threadLocal.get();

源碼淺析

  • 通過構(gòu)造函數(shù)我們發(fā)現(xiàn),ThreadLocal在構(gòu)造函數(shù)中并沒有做任何操作,所以我們從set方法作為入口進(jìn)行分析。
public void set(T value) {
  Thread t = Thread.currentThread();
  ThreadLocalMap map = getMap(t);
 if (map != null)
    map.set(this, value);
 else  
   createMap(t, value);
}

通過set方法我們可以看到,ThreadLocal實(shí)際是在其內(nèi)部維護(hù)了一個(gè)ThreadLocalMap實(shí)例進(jìn)行變量的存儲(chǔ),并把該實(shí)例與線程進(jìn)行綁定。在ThreadLocalMap中key的值為this,也就是當(dāng)前線程的ThreadLocal實(shí)例,value為當(dāng)前設(shè)置的值

  • 在get方法中,通過調(diào)用ThreadLocalMap map = getMap(t);獲取當(dāng)前線程綁定的ThreadLocalMap實(shí)例,并獲取value值。

  • 值得注意的是ThreadLocal同一線程只能存儲(chǔ)一個(gè)值,如果需要存儲(chǔ)多個(gè)值,可以考慮封裝成一個(gè)對(duì)象進(jìn)行存儲(chǔ)。

默認(rèn)值

  • ThreadLocal通過protected T initialValue()方法進(jìn)行value的初始化。
protected T initialValue() {
    return null;
}

  • 通過源碼我們可以看到,該方法直接返回null。所以在創(chuàng)建實(shí)例后直接調(diào)用get方法時(shí),我們得到的是空值。如果我們需要在ThreadLocal實(shí)例創(chuàng)建的時(shí)候進(jìn)行初始化,可以通過繼承ThreadLocal并重寫initialValue()方法即可。
  • 那么initialValue()方法在何時(shí)進(jìn)行調(diào)用的呢?通過查找源碼我們?cè)趃et方法中看到了該方法的調(diào)用。
public T get() {
  Thread t = Thread.currentThread();
  ThreadLocalMap map = getMap(t);
 if (map != null) {
   ThreadLocalMap.Entry e = map.getEntry(this);
   if (e != null) {
     @SuppressWarnings("unchecked")
     T result = (T)e.value;
     return result;
    }
    }
    return setInitialValue(); 
  • 通過get方法執(zhí)行流程可以看到,當(dāng)ThreadLocal創(chuàng)建實(shí)例的時(shí)候,ThreadLocalMap map = getMap(t);返回的map值肯定為空,所以執(zhí)行setInitialValue();并返回,我們進(jìn)入該方法:
private T setInitialValue() {
  T value = initialValue(); //目標(biāo)代碼
  Thread t = Thread.currentThread();
  ThreadLocalMap map = getMap(t);
 if (map != null)
    map.set(this, value);
 else  createMap(t, value);
   return value;
}
  • 從setInitialValue方法實(shí)現(xiàn)可以看到,在該方法中調(diào)用了initialValue返回了我們自定義的返回值,并設(shè)置到ThreadLocalMap實(shí)例中。

  • 通過上面的查看源碼可以發(fā)現(xiàn),ThreadLocal在設(shè)置初始化值時(shí),需要在第一次調(diào)用get方法時(shí)才會(huì)進(jìn)行初始化,而不是在實(shí)例創(chuàng)建的時(shí)候進(jìn)行初始化。

以上即為個(gè)人對(duì)ThreadLocal的簡(jiǎn)單理解。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容