線程內(nèi)部存儲(chǔ)---TheadLocal從使用到源碼分析

ThreadLocal是什么?

ThreadLocalThreadLocal是一個(gè)線程內(nèi)部用于存儲(chǔ)數(shù)據(jù)的類,通過它可以在指定的線程中存儲(chǔ)數(shù)據(jù),數(shù)據(jù)存儲(chǔ)以后,只有在該線程中可以獲取到存儲(chǔ)的數(shù)據(jù),對(duì)于其它線程來說無法獲取到數(shù)據(jù)。個(gè)人認(rèn)為是一個(gè)線程內(nèi)部的存儲(chǔ)機(jī)制。

如何使用?

ThreadLocal<Boolean> threadLocal = new ThreadLocal<>();

這樣就在一個(gè)線程創(chuàng)建了ThreadLocal這個(gè)對(duì)象,這個(gè)對(duì)象支持范性的,也就是說我們可以存儲(chǔ)的自己想存的任意類型。

  threadLocal.set(true);

這樣我們就在當(dāng)前所在線程,存儲(chǔ)了true。

new Thread("Thread#1") {
      @Override
       public void run() {
            System.out.println(threadLocal.get());
           };
        }.start();

我們?cè)谝粋€(gè)分線程去打印這個(gè)剛才存儲(chǔ)的值會(huì)發(fā)現(xiàn)是null,因?yàn)檫@是在兩個(gè)線程操作的。如果在當(dāng)前線程獲取則為正確剛才存的值。
如果想移除這個(gè)數(shù)據(jù)也很簡單:

threadLocal.remove();

這就是threadLocal的使用,其實(shí)很簡單。 主要記得是區(qū)分線程的就ok。

內(nèi)部源碼是如何實(shí)現(xiàn)的呢?

image.png

這就是treadLocal中的所有方法了,其實(shí)我們最關(guān)心的就是set和get方法。

我們先看set:

 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方法,對(duì)就這么幾行。
首先會(huì)通過Thread.currentThread();這個(gè)方法獲取當(dāng)前線程的Thread。然后通過getMap()獲取 ThreadLocalMap對(duì)象。

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

getMap中也很簡單,就是返回這個(gè)線程的threadLocals, 這個(gè)ThreadLocal就是 Thread中的一個(gè)變量ThreadLocal.ThreadLocalMap threadLocals = null;
其實(shí)還是ThreadLocal中的內(nèi)部類ThreadLocalMap;這里一會(huì)在分析,先順著思路往下走。
獲取map之后會(huì)根據(jù)判斷如果不是null就進(jìn)行set,也就是存儲(chǔ),如果是null就會(huì)調(diào)用createMap()方法進(jìn)行創(chuàng)建這個(gè)ThreadMap。接下來在看是如何set和createMap的。

創(chuàng)建其實(shí)很簡單,直接就是new一個(gè)。

   void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

set方法就稍微復(fù)雜了些,因?yàn)檫@也是核心內(nèi)容。set方法在內(nèi)部類ThreadLocalMap中,所以接下來分析下這個(gè)ThreadLocalMap類。

ThreadLocalMap

這個(gè)類在構(gòu)造中創(chuàng)建了一個(gè)數(shù)組, new Entry[INITIAL_CAPACITY]; ,Entry里面就是一個(gè)object的對(duì)象,然后里面主要getEntry和set方法進(jìn)行存取和讀取。

   private void set(ThreadLocal key, Object value) {

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal k = e.get();

                if (k == key) {//這里判斷這個(gè)k和傳進(jìn)來的key是否相等
                    e.value = value;//進(jìn)行存儲(chǔ)后return
                    return;
                }

                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

看主要代碼 判斷k和傳進(jìn)來的key相等話就存儲(chǔ)這個(gè)value
get方法:

private Entry getEntry(ThreadLocal<?> key) {
   int i = key.threadLocalHashCode & (table.length - 1);//根據(jù)key獲取位下標(biāo)
            Entry e = table[i];  // 根據(jù)下標(biāo),獲取這個(gè)Entry 里面是一個(gè)object,實(shí)現(xiàn)了軟引用
            if (e != null && e.get() == key)
                return e; //校驗(yàn)沒問題后返回
            else
                return getEntryAfterMiss(key, i, e);
        }

我們?cè)倏磄et:

  public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

get里面也是要先獲取當(dāng)前的Thread這也就是為什么ThreadLocal獲取和存儲(chǔ)的都是只在當(dāng)前線程的。

然后也是getMap方法獲取這個(gè)ThreadLocalMap,這也就是為什么里面就一行代碼,也要寫成一個(gè)方來,因?yàn)檫@是中思路,其他地方獲取直接調(diào)用就行,日后擴(kuò)展的話一樣方便。

再然后就是通過這個(gè)map去調(diào)用上面說的getEntry方法。

至此,我們就知道ThreadLocal的總體工作流程和思路了。

最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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