天天看點

threadlocal原理_ThreadLocal初體驗

前些日子遇到一個需求,要在消息清單對之前版本的做消息詳情的相容,做相容很簡單,無非就是擷取版本号做一個不同的實作。但是惡心的是需要把這個版本号一層一層的從方法裡傳遞進來,其實看之前所有的相容,都是在最初的方法中後續增加appVersion來實作相容功能,那有沒有什麼辦法可以實作不通過傳遞參數也能擷取到版本号呢?直到遇到了threadLocal

——什麼是ThreadLocal?

jdk中是這麼解釋的

threadlocal原理_ThreadLocal初體驗

意思大概是ThreadLocal提供線程内的局部變量,這些變量在多線程通路時能保證各個線程中的變量相對獨立于于其他線程中的變量。ThreadLocal執行個體通常來說是private static類型的,用來關聯線程和線程的上下文。

總結一下呢,就是它提供線程内的局部變量,在本線程裡即取即用,可以減少函數裡公共變量傳遞的複雜度。

——舉個

既然把threadLocal寫的這麼神奇,我們不妨來試一試吧

首先我們先定義一個threadLocal,并給予初始值

threadlocal原理_ThreadLocal初體驗

之後我們定義線程,并對這些線程進行加法操作

threadlocal原理_ThreadLocal初體驗

輸出結果

threadlocal原理_ThreadLocal初體驗

從結果中我們可以看到,各個線程之間的值時互相隔離的

——原理

那threadLocal的内部實作是怎麼樣的呢?

這裡我們要了解一下threadLocal的三個方法,也是我們主要用到的三個方法:

public T get()

get方法:擷取目前threadLocal的值,如果沒有則傳回預設值

public void set(T value)

set 方法:用來設定目前threadLocal的值

public void remove()

remove方法:用來删除目前threadLocal的值

我們來看看get方法

threadlocal原理_ThreadLocal初體驗

首先擷取目前線程,再通過目前線程擷取threadLocalMap

threadlocal原理_ThreadLocal初體驗

在getMap方法中,我們發現擷取到的是目前線程的一個成員變量threadsLocals

threadlocal原理_ThreadLocal初體驗

這個threadLocals其實就是threadLocalMap,是threadLocal的一個内部類

threadlocal原理_ThreadLocal初體驗

而在threadLocalMap中,我們可以看到,它繼承了弱引用,用treadLocal作為key,使用者需要傳遞的副本變量作為value

繼續來看setInitialValue方法

threadlocal原理_ThreadLocal初體驗

很直覺的可以看到,當map不為空時,設定鍵值對,當value為空時,則去建立一個map

threadlocal原理_ThreadLocal初體驗

其實從一個get方法中,我們就大概明白了threadLocal的原理

每個線程都有一個 threadLocal.threadLocalMap 類型的成員變量threadLocals,這個threadLocals就是用來存儲我們需要傳遞的變量,key為目前的threadLocal,value為變量;

開始時,用set方法對thread中的threadLocals初始化,目前hreadLocal變量為鍵值,以ThreadLocal要儲存的副本變量為value,存到threadLocals;當需要使用時,就可以通過get方法擷取到變量,當然這個前提是在同一個線程中。

——小結

注意,劃重點啦!~

1.每個threadLocal建立的變量其實是存儲在每個線程自己的threadLocals中

2.為什麼要用threadLocal作為key而不用每個線程的id呢?因為一個線程中是可以有多個threadLocal的,如果用線程id作為key,那就不知道如何區分放進threadLocals的value啦

3.在沒有重寫setInitValue前提下,要先set再get,預設的值為null會導緻空指針哦