這篇文章主要介紹ThreadLocal原理是什么,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
成都創(chuàng)新互聯(lián)公司專注于祁縣網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供祁縣營銷型網(wǎng)站建設(shè),祁縣網(wǎng)站制作、祁縣網(wǎng)頁設(shè)計(jì)、祁縣網(wǎng)站官網(wǎng)定制、微信小程序開發(fā)服務(wù),打造祁縣網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供祁縣網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
ThreadLocal即線程局部變量的意思!所以什么是線程局部變量?這玩意有什么鳥用?是不是面試被問到了說不出個(gè)一二三?今天就來扒一扒這貨的源碼,從根本上了解這貨是干啥的。
Thread、ThreadLocalMap、Entry三者關(guān)系
其實(shí)研究下來他的源碼實(shí)現(xiàn),其實(shí)也沒想象的那么復(fù)雜,其最主要有以下幾點(diǎn):
1、Java可以通過Thread.currentThread()來獲得當(dāng)前的Thread的實(shí)例對(duì)象。既然能拿到這Thread對(duì)象實(shí)例,那么我們就可以操作該實(shí)例(的屬性),比如為該Thread對(duì)象設(shè)置一個(gè)值什么。
2、每一個(gè)Thread對(duì)象都有一個(gè)ThradLocalMap實(shí)例,該實(shí)例有一個(gè)一個(gè)Entry組成的數(shù)組,Entry對(duì)象有兩個(gè)主要屬性:value和ThreadLocal的弱引用,其中value這個(gè)屬性就是值設(shè)置給當(dāng)前線程所持有,也是ThreadLocal的核心屬性:
static class Entry extends WeakReference> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal> k, Object v) { super(k); value = v; } }
注意Entry繼承自WeakReference,其key就是ThreadLocal對(duì)象?。▓D1)
結(jié)合1和2兩個(gè)知識(shí)點(diǎn),我們就可以知道我們拿到Thread對(duì)象之后,就可以操控當(dāng)前線程對(duì)象的ThreadLocalMap對(duì)象,然后把想要保存的value交給ThreadLocalMap的Entry的value屬性,Thread,ThreadLocalMap,value三者之間的關(guān)系可以用下圖表示(圖2):
通過上圖我們可以得出這么一個(gè)結(jié)論:一個(gè)Thread對(duì)象持有一個(gè)ThreadLocalMap對(duì)象,然后呢,一個(gè)ThreadLoalMap對(duì)象又包含了多個(gè)ThreadLlocal對(duì)象及ThreadLocal對(duì)象所在線程的value?。?!一言以蔽之: 一個(gè)Thread對(duì)象可以持有多個(gè)ThreadLocal對(duì)象的變量值value
那么ThreadLocal和Thread又有啥關(guān)系呢?二者是怎能對(duì)value進(jìn)行讀取的呢?下面就根據(jù)源碼來簡(jiǎn)單的分析下。
ThreadLocal和Thread的關(guān)聯(lián)
先看看ThreadLocal的set方法:
public void set(T value) { //獲取當(dāng)前線程 Thread t = Thread.currentThread(); //獲取當(dāng)前線程持有的ThreadLocalMap ThreadLocal.ThreadLocalMap map = getMap(t); //將value設(shè)置給threadlocalMap if (map != null) map.set(this, value); else createMap(t, value); }
set方法很邏輯很簡(jiǎn)單(j結(jié)合上圖2看更好理解):
1、通過currentThread方法拿到當(dāng)前Thread對(duì)象
2、獲取當(dāng)前Thread對(duì)象的ThreadLoalMap對(duì)象
3、將value連同ThreadLocal對(duì)象自己組成一個(gè)Entry對(duì)象保存在
ThreadLoalMap的Entry類型的數(shù)組中。
在來看看ThreadLocal的get方法:
public T get() { //獲取當(dāng)前線程 Thread t = Thread.currentThread(); //獲取當(dāng)前線程的ThreadLocalMap對(duì)象 ThreadLocalMap map = getMap(t); if (map != null) { //獲取與ThreadLocal對(duì)象想關(guān)聯(lián)的value ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") //獲取值 T result = (T)e.value; return result; } } //為空返回初始化值 return setInitialValue(); }
可以發(fā)展get的整體邏輯也很簡(jiǎn)單:
1、獲取當(dāng)前Thread對(duì)象
2、獲取當(dāng)前Thread對(duì)象的ThreadLocalMap對(duì)象
3、從ThreadLocalMap中獲取與ThreadLocal相關(guān)聯(lián)的Entry對(duì)象,具體的就是以ThreadLocal為key獲取。
4、獲取步驟3的Entry的value屬性,并返回之。
通過整體觀察get和set方法可以得出如下結(jié)論:ThreadLocal對(duì)象調(diào)用set方法就是往Thread對(duì)象的ThreadLocalMap里面添加值;ThreadLocal對(duì)象調(diào)用get方法就是從Thread對(duì)象的ThreadLocalMap里面獲取值。核心就是操縱Thread對(duì)象的ThreadLocalMap對(duì)象進(jìn)行value的讀和寫。原理就這么簡(jiǎn)單。
那么位于不同線程的不同ThreadLocal對(duì)象,在其他線程里保存值是一個(gè)什么樣的關(guān)系呢?可以通過下圖來清晰的描述出來:
ThreadLocal的使用實(shí)例
我們?cè)谥涝贏ndroid中一個(gè)線程只有一個(gè)Looper對(duì)象,那么是怎么做到的呢?就是ThreadLocal發(fā)揮了作用,看看Looper的prepare方法:
//定義一個(gè)靜態(tài)的ThreadLocal變量 static final ThreadLocalsThreadLocal = new ThreadLocal (); private static void prepare(boolean quitAllowed) { //一個(gè)Thread只能關(guān)聯(lián)一個(gè)Looper對(duì)象 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
觀察prepare方法可以知道,先通過sThreadLocal的get方法判斷當(dāng)前線程是否已經(jīng)擁有了一個(gè)Looper對(duì)象,如果有就拋出一個(gè)異常;如果當(dāng)前線程還沒有設(shè)置Looper對(duì)象,則調(diào)用ThreadLocal的set方法,初始化一個(gè)Looper對(duì)象交給當(dāng)前線程:
sThreadLocal.set(new Looper(quitAllowed));
這樣就確保了一個(gè)線程只有一個(gè)Looper對(duì)象。
到此為止,關(guān)于ThreadLocal的原理已經(jīng)基本分析完畢,至于內(nèi)部是怎么set和get的,博主并沒有做太細(xì)的分析,因?yàn)闆]必要,了解ThreadLocal的工作原因以及使用場(chǎng)景即可。
以上是ThreadLocal原理是什么的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!