共享變數一直是併發中的老大難問題,每個執行緒都對它有操作權,所以執行緒之間的同步很關鍵,鎖也就應運而生。這裡換乙個思路,是否可以把共享變數私有化?即每個執行緒都擁有乙份共享變數的本地副本,每個執行緒對應乙個副本,同時對共享變數的操作也改為對屬於自己的副本的操作,這樣每個執行緒處理自己的本地變數,形成資料隔離。事實上這就是threadlocal了。
我們可能每天都在使用spring寫dao寫service,真的是乙個非常爽的框架.我們能用這麼爽是因為spring在底層把髒活兒累活兒全乾了。在乙個service中我們可能要寫很多個dao,如果多個dao都用不同的jdbc連線,很費時費力費資源不說,事務性就得不到保證了,因為我們知道事務需要在乙個連線內才能得以實現。事務對應著連線,所以如果我們每個執行緒對應乙個連線,也就能保證我們在乙個service中很爽的叨叨叨了,spring底層正是使用threadlocal對連線進行了封裝,可勁兒叨吧你就
看完應用場景似乎對threadlocal已經有所了解,不過,本著知其然並知其所以然的心態,還是去看看原始碼怎麼實現的吧
先去thread類中瞄一眼,thread中有2個成員變數
threadlocal.threadlocalmap threadlocals = null;
threadlocal.threadlocalmap inheritablethreadlocals = null;
兩個變數都是threadlocalmap類,咦?說了半天 threadlocal怎麼又冒出來個threadlocalmap
是這樣子的,預設這兩個變數都是null,正如我們現在看到的。
一旦我們呼叫threadlocal的set或者get才會真正建立他們。也就是你以為你把變數交給threadlocal了,其實這小子轉手就給threadlocalmap了,threadlocal就是套在 threadlocalmap外面的一層殼而已。
threadlocal的組成如下
可以看出,就跟map基本一樣,key是threadlocal的引用,value則是由開發者設定,即本地變數
set
public void set(t value)
void createmap(thread t, t firstvalue)
首先獲取當前執行緒
以當前執行緒為key去查詢當前執行緒的map即threadlocals變數
如果threadlocals不為空,就把threadlocal引用作為key,value傳給map
否則建立map,也就是初始化當前執行緒的threadlocals變數
再次注意值存放的實際位置是thread中的threadlocalmap變數,threadlocalmap是乙個map,key是threadlocal的例項引用,值則是我們要存的變數get
public t get()
}return setinitialvalue();
}
其實就很簡單了,set的反過程嘛,先得到當前執行緒,然後得到成員變數threadlocals,如果threadlocals不為空,返回本地變數對應值,否則初始化threadlocals
初始化threadlocals
private t setinitialvalue()
protected t initialvalue()
判斷當前threadlocals是否為空,如果不為空,設定當前threadlocal的例項引用對應變數為null,否則呼叫createmap建立threadlocals變數
remove()
public void remove()
如果threadlocals變數不為空,刪掉map中當前threadlocal對應例項引用的本地變數。
從上邊一路走下來我們應該了解了,每乙個執行緒中都有乙個threadlocalmap
型別的threadlocals變數,這個map中key為threadlocal的例項引用,value為對應的本地變數。如果這個執行緒不消亡,開發者也沒有採用remove操作及時清除掉不再使用的變數,這些變數就會一直存在map中,直到撐爆你的記憶體,造成記憶體溢位問題
假設乙個場景,我們需要非同步起乙個執行緒傳送郵件給使用者,子執行緒需要打日誌,那麼就需要父執行緒中本地變數,這裡子執行緒可以通過父執行緒的threadlocal得到父執行緒設定的的本地變數嗎?答案是不可以,threadlocal不支援父子執行緒間的繼承傳遞
這裡可以使用inheritablethreadlocal,沒錯就是上邊日誌那塊我們提到過的。它是threadlocal的子類,其實用法跟threadlocal完全一樣,不過,它可以使得子執行緒訪問在父執行緒中設定的變數,簡單看下這一實現的原理
首先看下執行緒的構造方法,說實話之前真沒看過這個構造方法,我覺得應該很多人都沒看過吧
public thread(runnable target)
這個init方法追進去,你會看到底下這行**,init方法體太長,我就只擷取出來這最關鍵的一部分
if (inheritthreadlocals && parent.inheritablethreadlocals != null)
this.inheritablethreadlocals =
threadlocal.createinheritedmap(parent.inheritablethreadlocals);
parent就是父執行緒,如果父執行緒中的inheritablethreadlocals 不為空,就執行 createinheritedmap
static threadlocalmap createinheritedmap(threadlocalmap parentmap)
這個**就不繼續展開了,過程就是把父執行緒中的 inheritablethreadlocals 的值全部複製乙份到子執行緒的 inheritablethreadlocals 中
每個執行緒對應乙個threadlocalmap,threadlocal其實就是套在threadlocalmap上的一層殼
threadlocalmap的key是threadlocal的例項引用,value是我們像設定的本地變數
若是執行緒一直不停,threadlocalmap中的本地變數就會越來越多,注意即使remove掉不再使用的變數,防止記憶體溢位
一文帶你搞懂Spring核心
容錯 減少延遲 提高效能 可用性負載均衡 總而言之,其實目的只有乙個,使用者體驗 分布式系統是由使用分發中介軟體連線的自治計算機組成的網路。它們有助於共享不同的資源和功能,為使用者提供單一且整合的連貫網路。1 在伺服器 虛擬機器 上安裝zookeeper 我這裡使用docker安裝 1 去docke...
一文帶你搞懂python中的property
通常我們在獲得變數的一些私有屬性時,必須通過方法來獲取私有屬性,並不能直接訪問 修改其數值的時候也是要通過方法去修改,這樣非常的不方便 所以python提供了一種方式,將呼叫方法的的形式轉變為訪問屬性,這樣使用非常方便 class student def init self 這是乙個私有屬性 sel...
Go學習 一文徹底搞懂go mod使用
jquery中文網為您提供一文徹底搞懂go mod使用等資源,歡迎您收藏本站,我們將為您提供最新的一文徹底搞懂go mod使用資源 目錄 一 如何使用go mod 二 golang開啟mod後import報紅解決 三 go mod 怎麼匯入本地其它專案的包?四 完整 此時專案可以放在任意位置,不必非...