threadlocal底層實現內部類:threadlocalmap
一、threadlocal的set方法原始碼分析:
(1)public void set(t value) {
thread t = thread.currentthread();
threadlocalmap map = getmap(t);
if (map != null)
map.set(this, value);
else
createmap(t, value);
1、thread t = thread.currentthread();
獲取當前執行緒物件t
2、threadlocalmap map = getmap(t);
獲取threadlocalmap物件,呼叫getmap方法,引數:thread t,將當前物件傳入到getmap方法,getmap的原始碼如(2)所示:
(2)threadlocalmap getmap(thread t) {
return t.threadlocals;
通過**分析得知:map的值是當前物件t中定義的threadlocalmap物件【也就是說map是屬於當前執行緒t中的屬性】。
3、如果map!=null,則執行map.set(this,value)。threadlocalmap中的key為threadlocal<?>物件。this將當前的threadlocal物件作為key。
4、如果map為null,則建立map,呼叫createmap(t,value),createmap原始碼如(3)所示:
(3)void createmap(thread t, t firstvalue) {
t.threadlocals = new threadlocalmap(this, firstvalue);
通過原始碼得知,初始化當前執行緒物件t的threadlocals例項。並且將value儲存到threadlocalmap中,將當前的threadlocal物件作為key。
注意:threadlocalmap例項是當前執行緒物件的屬性,並且threadlocalmap中的key是當前threadlocal物件。
二、threadlocal的get方法原始碼分析:
public t get() {
thread t = thread.currentthread();
threadlocalmap map = getmap(t);
if (map != null) {
threadlocalmap.entry e = map.getentry(this);
if (e != null) {
@suppresswarnings("unchecked")
t result = (t)e.value;
return result;
return setinitialvalue();
1、thread t = thread.currentthread();獲取當前執行緒物件t。
2、threadlocalmap map = getmap(t);通過以上原始碼得知,返回當前執行緒物件t的threadlocals例項。
(2-1)
private entry getentry(threadlocal<?> key) {
int i = key.threadlocalhashcode & (table.length - 1);
entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getentryaftermiss(key, i, e);
3.1、e.get() 呼叫的是weakreference中的get方法,返回的是threadlocal物件,即threadlocalmap的key值。
如果e.get()==key,則返回entry物件。否則,執行getentryaftermiss(key,i,e),原始碼如(2-2)
(2-2)
private entry getentryaftermiss(threadlocal<?> key, int i, entry e) {
entry tab = table;
int len = tab.length;
while (e != null) {
threadlocal<?> k = e.get();
if (k == key)
return e;
if (k == null)
expungestaleentry(i);
else
i = nextindex(i, len);
e = tab[i];
return null;
3.2、如果e!=null,則執行e.get()獲取threadlocal物件k,
如果k==key,則返回e;
如果k==null,則執行expungestaleentry(i);//刪除過期的entry物件,【如果key為null,則entry物件為過期物件】
如果k!=null && k!=key,執行i=nextindex(i,len)則獲取tab[ ]陣列的下乙個索引,
e=tab[i]繼續從tab[ ]陣列中獲取entry物件e。執行3.2操作。
3.3、如果e!=null,則直接獲取e.value返回。如果e==null,則執行:setinitialvalue();
4、如果 map==null,則執行:setinitialvalue();原始碼(2-3)如下:
(2-3)
private t setinitialvalue() {
t value = initialvalue();
thread t = thread.currentthread();
threadlocalmap map = getmap(t);
if (map != null)
map.set(this, value);
else
createmap(t, value);
return value;
(2-4)
protected t initialvalue() {
return null;
4.1、初始化value,執行initialvalue()方法,返回null。原始碼(2-4)
4.2、獲取當前執行緒物件t
4.3、呼叫getmap(t),獲取threadlocalmap物件。
4.4、如果map!=null,則執行map.set(this,value);否則,執行createmap(t,value),建立threadlocalmap,並且設定key與value。返回value。【value值為null】
三、原理
執行緒共享變數快取如下:
thread.threadlocalmap;
1、thread: 當前執行緒,可以通過thread.currentthread()獲取。
2、threadlocal:我們的static threadlocal變數。
3、object: 當前執行緒共享變數。
我們呼叫threadlocal.get方法時,實際上是從當前執行緒中獲取threadlocalmap,然後根據當前threadlocal獲取當前執行緒共享變數object。
threadlocal.set,threadlocal.remove實際上是同樣的道理。
這種儲存結構的好處:
1、執行緒死去的時候,執行緒共享變數threadlocalmap則銷毀。
2、threadlocalmap鍵值對數量為threadlocal的數量,一般來說threadlocal數量很少,相比在threadlocal中用map鍵值對儲存執行緒共享變數(thread數量一般來說比threadlocal數量多),效能提高很多。
關於threadlocalmap弱引用問題:
當執行緒沒有結束,但是threadlocal已經被**,則可能導致執行緒中存在threadlocalmap的鍵值對,造成記憶體洩露。(threadlocal被**,threadlocal關聯的執行緒共享變數還存在)。
雖然threadlocal的get,set方法可以清除threadlocalmap中key為null的value,但是get,set方法在記憶體洩露後並不會必然呼叫,所以為了防止此類情況的出現,我們有兩種手段。
1、使用完執行緒共享變數後,顯示呼叫threadlocalmap.remove方法清除執行緒共享變數;
2、jdk建議threadlocal定義為private static,這樣threadlocal的弱引用問題則不存在了。
ThreadLocal實現原理
threadlocal,即執行緒區域性變數,其實就是乙個容器,每個執行緒都可通過其set方法儲存乙份資料,並且在get時只會獲取自己執行緒的資料,是常用的實現執行緒安全的方式。自己用過許多次了,但沒有細究其原理,今天大概看了一下原始碼,算是明白了一點點0.0 直接看threadlocal的get方法...
ThreadLocal底層實現原理
解釋的不錯的一片文章 下邊是個人理解,如果有錯誤還請批評指正 首先說一下使用方式 threadlocalthreadlocala new threadlocal threadlocalthreadlocalb new threadlocal 存入 執行緒1 threadlocala.set aaa ...
ThreadLocal實現原理簡述
threadlocal是乙個執行緒內共享變數工具類。將執行緒與該執行緒存放的物件做乙個對映,各個執行緒之間的變數互不干擾。適用於各個執行緒依賴不同的變數值完成操作的場景,如 spring宣告式資料庫事務 shiro的session threadlocal內部結構 核心機制 1.每個執行緒例項中有個t...