首先,它是乙個資料結構,有點像hashmap,可以儲存"key : value"鍵值對,但是乙個threadlocal只能儲存乙個,並且各個執行緒的資料互不干擾。
1 threadlocallocalname = new這是為什麼,如何實現?不過之前也說了,threadlocal保證了各個執行緒的資料互不干擾。threadlocal();
2 localname.set("尋夢");
3 string name = localname.get();
看看set(t value)
和get()
方法的原始碼
public可以發現,每個執行緒中都有乙個void
set(t value)
public
t get()
}return
setinitialvalue();}
threadlocalmap getmap(thread t)
threadlocalmap
資料結構,當執行set方法時,其值是儲存在當前執行緒的threadlocals
變數中,當執行set方法中,是從當前執行緒的threadlocals
變數獲取。
那每個執行緒中的threadloalmap
究竟是什麼?
本文分析的是1.7的原始碼。
從名字上看,可以猜到它也是乙個類似hashmap的資料結構,但是在threadlocal中,並沒實現map介面。
在threadloalmap中,也是初始化乙個大小16的entry陣列,entry物件用來儲存每乙個key-value鍵值對,只不過這裡的key永遠都是threadlocal物件,是不是很神奇,通過threadlocal物件的set方法,結果把threadlocal物件自己當做key,放進了threadloalmap中。
這裡需要注意的是,threadloalmap的entry是繼承weakreference,和hashmap很大的區別是,entry中沒有next欄位,所以就不存在鍊錶的情況了。
沒有鍊錶結構,那發生hash衝突了怎麼辦?
先看看threadloalmap中插入乙個key-value的實現
private每個threadlocal物件都有乙個hash值void set(threadlocal>key, object value)
if (k == null
) }
tab[i] = new
entry(key, value);
int sz = ++size;
if (!cleansomeslots(i, sz) && sz >=threshold)
rehash();
}
threadlocalhashcode
,每初始化乙個threadlocal物件,hash值就增加乙個固定的大小0x61c88647
。
在插入過程中,根據threadlocal物件的hash值,定位到table中的位置i,過程如下:1、如果當前位置是空的,那麼正好,就初始化乙個entry物件放在位置i上;2、不巧,位置i已經有entry物件了,如果這個entry物件的key正好是即將設定的key,那麼重新設定entry中的value;3、很不巧,位置i的entry物件,和即將設定的key沒關係,那麼只能找下乙個空位置;
這樣的話,在get的時候,也會根據threadlocal物件的hash值,定位到table中的位置,然後判斷該位置entry物件中的key是否和get的key一致,如果不一致,就判斷下乙個位置
可以發現,set和get如果衝突嚴重的話,效率很低,因為threadloalmap是thread的乙個屬性,所以即使在自己的**中控制了設定的元素個數,但還是不能控制其它**的行為。
threadlocal可能導致記憶體洩漏,為什麼?先看看entry的實現:
static通過之前的分析已經知道,當使用threadlocal儲存乙個value時,會在threadlocalmap中的陣列插入乙個entry物件,按理說key-value都應該以強引用儲存在entry物件中,但在threadlocalmap的實現中,key被儲存到了weakreference物件中。class entry extends weakreference>
}
這就導致了乙個問題,threadlocal在沒有外部強引用時,發生gc時會被**,如果建立threadlocal的執行緒一直持續執行,那麼這個entry物件中的value就有可能一直得不到**,發生記憶體洩露。
如何避免記憶體洩露
既然已經發現有記憶體洩露的隱患,自然有應對的策略,在呼叫threadlocal的get()、set()可能會清除threadlocalmap中key為null的entry物件,這樣對應的value就沒有gc roots可達了,下次gc的時候就可以被**,當然如果呼叫remove方法,肯定會刪除對應的entry物件。
如果使用threadlocal的set方法之後,沒有顯示的呼叫remove方法,就有可能發生記憶體洩露,所以養成良好的程式設計習慣十分重要,使用完threadlocal之後,記得呼叫remove方法。
threadlocallocalname = newthreadlocal();
try finally
ThreadLocal原理詳解
threadlocal稱為執行緒本地變數,其為變數在每個執行緒中都建立了乙個副本,每個執行緒都訪問和修改本執行緒中變數的副本。應用示例 可以看出,為每個執行緒分配乙個變數副本的工作並不是由threadlocal實現的,需要在應用層面實現,threadlocal只是提供乙個容器。如果在應用上為每個執行...
ThreadLocal用法詳解和原理
一 用法 threadlocal用於儲存某個執行緒共享變數 對於同乙個static threadlocal,不同執行緒只能從中get,set,remove自己的變數,而不會影響其他執行緒的變數。1 threadlocal.get 獲取threadlocal中當前執行緒共享變數的值。2 threadl...
ThreadLocal原理探尋
筆者今天趁著專案空隙,學習了下threadlocal這個類,探尋了下多執行緒下如何實現執行緒安全的原理。分享下 package com.suning.sample.transcation public class threadtest public static void main string a...