ThreadLocal In Java 8

TheadLocal 是一個(gè)線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類笛园,通常用于存儲(chǔ)以線程為作用域的數(shù)據(jù)變量弥搞,避免產(chǎn)生多線程的同步問題。
記得上學(xué)時(shí)候也寫過相關(guān)源碼的分析文章医舆,但今天翻看Java 8中的ThreadLocal類時(shí)發(fā)現(xiàn)它被重構(gòu)了竭翠,因此也重讀一下相關(guān)源碼實(shí)現(xiàn)振坚。
ThreadLocal是一個(gè)泛型類,定義如下:

public class ThreadLocal<T>

作為存儲(chǔ)類斋扰,我們抓住主要矛盾從setget方法開始分析渡八。

ThreadLocal 存數(shù)據(jù) —— set方法


    public void set(T value) {
        //獲取到當(dāng)前線程
        Thread t = Thread.currentThread();
        //根據(jù)當(dāng)前線程獲取ThreadLocalMap對象
        ThreadLocalMap map = getMap(t);
        
        if (map != null) // map對象不為空則存入對象
            map.set(this, value);
        else // 否則創(chuàng)建ThreadLocalMap
            createMap(t, value);
    }

可以看到,set方法向一個(gè)ThreadLocalMap對象中存入數(shù)據(jù)传货,ThreadLocalMapThreadLocal的靜態(tài)內(nèi)部類呀狼,具體實(shí)現(xiàn)我們隨后進(jìn)行分析。我們現(xiàn)在只需知道它被用來存儲(chǔ)數(shù)據(jù)(像HashMap那樣):key是線程對應(yīng)的threadlocal對象损离,value是要存入的數(shù)據(jù)對象哥艇。

作者的叨叨:其實(shí)看到這里機(jī)智點(diǎn)的小伙伴可以嘗試猜測整個(gè)ThreadLocal類的實(shí)現(xiàn)原理。
先別管這樣的猜測是不是正確僻澎,這不重要貌踏。其實(shí)我們看源碼的時(shí)候要養(yǎng)成主動(dòng)思考的習(xí)慣,假如讓你來設(shè)計(jì)或者實(shí)現(xiàn)這樣的方案窟勃,你會(huì)怎么設(shè)計(jì)祖乳?然后再與實(shí)際源碼對比一下,并且關(guān)注一下源碼的細(xì)節(jié)秉氧。

下面我們接著看一下如何獲取之前存入的數(shù)據(jù)對象眷昆。

ThreadLocal 取數(shù)據(jù) —— get方法


    public T get() {
        //獲取到當(dāng)前線程
        Thread t = Thread.currentThread();
        //獲取ThreadLocalMap對象
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        //獲取ThreadLocalMap中的Entry對象并拿到Value
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        //如果之前未創(chuàng)建過ThreadLocalMap,則返回null
        return setInitialValue();
    }

從get方法中我們可以看到汁咏,如果當(dāng)前線程之前向ThreadLocalMap存入過數(shù)據(jù)對象亚斋,則根據(jù)線程實(shí)例獲取到存入的數(shù)據(jù)對象。

看完了存取兩個(gè)動(dòng)作攘滩,讓我們揭開ThreadLocalMap的面紗帅刊,看看ThreadLocal是如何存儲(chǔ)數(shù)據(jù)對象的。

ThreadLocal 儲(chǔ)數(shù)據(jù) —— ThreadLocalMap


從上面的set和get方法中都可以看到漂问,ThreadLocal一直在對ThreadLocalMap進(jìn)行操作赖瞒。我們來搞清楚Thread女揭,ThreadLocal以及ThreadLocalMap三者之間的關(guān)系。
在Thread類中可以看到栏饮,每個(gè)Thread對象中都持有一個(gè)ThreadLocalMap成員變量:

 ThreadLocal.ThreadLocalMap threadLocals = null;

在上面的set方法中我們看到了對ThreadLocalMap的創(chuàng)建:

    void createMap(Thread t, T firstValue) {
        //創(chuàng)建一個(gè)ThreadLocalMap對象賦值給當(dāng)前線程的成員變量threadLocals
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }
    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
        table = new Entry[INITIAL_CAPACITY];
        int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
        table[i] = new Entry(firstKey, firstValue);
        size = 1;
        setThreshold(INITIAL_CAPACITY);
    }

從構(gòu)造函數(shù)中我們可以看到ThreadLocalMap中維護(hù)了一個(gè)Entry對象的數(shù)組table:

private Entry[] table;
static class Entry extends WeakReference<ThreadLocal<?>> {
        /** The value associated with this ThreadLocal. */
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
            super(k);
            value = v;
        }
    }

Entry對象是一種類似<ThreadLocal吧兔,Object>鍵值對的結(jié)構(gòu),每個(gè)ThreadLocal對象都對應(yīng)了各自的數(shù)據(jù)對象∨坻遥現(xiàn)在Thread境蔼,ThreadLocal以及ThreadLocalMap三者之間的關(guān)系就清楚了:

relationship.png

通過ThreadLocalMap和Thread的一一對應(yīng)關(guān)系實(shí)現(xiàn)了線程作用域中的數(shù)據(jù)對象存取。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末冬竟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子民逼,更是在濱河造成了極大的恐慌泵殴,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拼苍,死亡現(xiàn)場離奇詭異笑诅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)疮鲫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門吆你,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人俊犯,你說我怎么就攤上這事妇多。” “怎么了燕侠?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵者祖,是天一觀的道長。 經(jīng)常有香客問我绢彤,道長七问,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任茫舶,我火速辦了婚禮械巡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饶氏。我一直安慰自己讥耗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布疹启。 她就那樣靜靜地躺著葛账,像睡著了一般。 火紅的嫁衣襯著肌膚如雪皮仁。 梳的紋絲不亂的頭發(fā)上籍琳,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天菲宴,我揣著相機(jī)與錄音,去河邊找鬼趋急。 笑死喝峦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呜达。 我是一名探鬼主播谣蠢,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼查近!你這毒婦竟也來了眉踱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤霜威,失蹤者是張志新(化名)和其女友劉穎谈喳,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體戈泼,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡婿禽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了大猛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扭倾。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖挽绩,靈堂內(nèi)的尸體忽然破棺而出膛壹,到底是詐尸還是另有隱情,我是刑警寧澤唉堪,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布恢筝,位于F島的核電站,受9級特大地震影響巨坊,放射性物質(zhì)發(fā)生泄漏撬槽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一趾撵、第九天 我趴在偏房一處隱蔽的房頂上張望侄柔。 院中可真熱鬧,春花似錦占调、人聲如沸暂题。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽薪者。三九已至,卻和暖如春剿涮,著一層夾襖步出監(jiān)牢的瞬間言津,已是汗流浹背攻人。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悬槽,地道東北人怀吻。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像初婆,于是被迫代替她去往敵國和親蓬坡。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容