這篇文章主要介紹ThreadLocal原理是什么,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
ThreadLocal即線程局部變量的意思!所以什么是線程局部變量?這玩意有什么鳥用?是不是面試被問到了說不出個一二三?今天就來扒一扒這貨的源碼,從根本上了解這貨是干啥的。
Thread、ThreadLocalMap、Entry三者關系
其實研究下來他的源碼實現,其實也沒想象的那么復雜,其最主要有以下幾點:
1、Java可以通過Thread.currentThread()來獲得當前的Thread的實例對象。既然能拿到這Thread對象實例,那么我們就可以操作該實例(的屬性),比如為該Thread對象設置一個值什么。
2、每一個Thread對象都有一個ThradLocalMap實例,該實例有一個一個Entry組成的數組,Entry對象有兩個主要屬性:value和ThreadLocal的弱引用,其中value這個屬性就是值設置給當前線程所持有,也是ThreadLocal的核心屬性:
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
注意Entry繼承自WeakReference,其key就是ThreadLocal對象?。▓D1)
結合1和2兩個知識點,我們就可以知道我們拿到Thread對象之后,就可以操控當前線程對象的ThreadLocalMap對象,然后把想要保存的value交給ThreadLocalMap的Entry的value屬性,Thread,ThreadLocalMap,value三者之間的關系可以用下圖表示(圖2):
通過上圖我們可以得出這么一個結論:一個Thread對象持有一個ThreadLocalMap對象,然后呢,一個ThreadLoalMap對象又包含了多個ThreadLlocal對象及ThreadLocal對象所在線程的value?。?!一言以蔽之: 一個Thread對象可以持有多個ThreadLocal對象的變量值value
那么ThreadLocal和Thread又有啥關系呢?二者是怎能對value進行讀取的呢?下面就根據源碼來簡單的分析下。
ThreadLocal和Thread的關聯
先看看ThreadLocal的set方法:
public void set(T value) { //獲取當前線程 Thread t = Thread.currentThread(); //獲取當前線程持有的ThreadLocalMap ThreadLocal.ThreadLocalMap map = getMap(t); //將value設置給threadlocalMap if (map != null) map.set(this, value); else createMap(t, value); }
set方法很邏輯很簡單(j結合上圖2看更好理解):
1、通過currentThread方法拿到當前Thread對象
2、獲取當前Thread對象的ThreadLoalMap對象
3、將value連同ThreadLocal對象自己組成一個Entry對象保存在
ThreadLoalMap的Entry類型的數組中。
在來看看ThreadLocal的get方法:
public T get() { //獲取當前線程 Thread t = Thread.currentThread(); //獲取當前線程的ThreadLocalMap對象 ThreadLocalMap map = getMap(t); if (map != null) { //獲取與ThreadLocal對象想關聯的value ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") //獲取值 T result = (T)e.value; return result; } } //為空返回初始化值 return setInitialValue(); }
可以發展get的整體邏輯也很簡單:
1、獲取當前Thread對象
2、獲取當前Thread對象的ThreadLocalMap對象
3、從ThreadLocalMap中獲取與ThreadLocal相關聯的Entry對象,具體的就是以ThreadLocal為key獲取。
4、獲取步驟3的Entry的value屬性,并返回之。
通過整體觀察get和set方法可以得出如下結論:ThreadLocal對象調用set方法就是往Thread對象的ThreadLocalMap里面添加值;ThreadLocal對象調用get方法就是從Thread對象的ThreadLocalMap里面獲取值。核心就是操縱Thread對象的ThreadLocalMap對象進行value的讀和寫。原理就這么簡單。
那么位于不同線程的不同ThreadLocal對象,在其他線程里保存值是一個什么樣的關系呢?可以通過下圖來清晰的描述出來:
ThreadLocal的使用實例
我們在知道在Android中一個線程只有一個Looper對象,那么是怎么做到的呢?就是ThreadLocal發揮了作用,看看Looper的prepare方法:
//定義一個靜態的ThreadLocal變量 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static void prepare(boolean quitAllowed) { //一個Thread只能關聯一個Looper對象 if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
觀察prepare方法可以知道,先通過sThreadLocal的get方法判斷當前線程是否已經擁有了一個Looper對象,如果有就拋出一個異常;如果當前線程還沒有設置Looper對象,則調用ThreadLocal的set方法,初始化一個Looper對象交給當前線程:
sThreadLocal.set(new Looper(quitAllowed));
這樣就確保了一個線程只有一個Looper對象。
到此為止,關于ThreadLocal的原理已經基本分析完畢,至于內部是怎么set和get的,博主并沒有做太細的分析,因為沒必要,了解ThreadLocal的工作原因以及使用場景即可。
以上是ThreadLocal原理是什么的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。