Java并發(fā)編程:深入剖析ThreadLocal-Java開(kāi)發(fā)Java經(jīng)驗(yàn)技巧_第1頁(yè)
Java并發(fā)編程:深入剖析ThreadLocal-Java開(kāi)發(fā)Java經(jīng)驗(yàn)技巧_第2頁(yè)
Java并發(fā)編程:深入剖析ThreadLocal-Java開(kāi)發(fā)Java經(jīng)驗(yàn)技巧_第3頁(yè)
Java并發(fā)編程:深入剖析ThreadLocal-Java開(kāi)發(fā)Java經(jīng)驗(yàn)技巧_第4頁(yè)
Java并發(fā)編程:深入剖析ThreadLocal-Java開(kāi)發(fā)Java經(jīng)驗(yàn)技巧_第5頁(yè)
已閱讀5頁(yè),還剩7頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、java并發(fā)編程:深入剖權(quán)thrcadlocal -編程 開(kāi)發(fā)技術(shù)java并發(fā)編程:深入剖析threadlocal原文出處:海子想必很多朋友對(duì)threadlocal并不陌生,今天我們就來(lái)一起探討下threadlocal 的使用方法和實(shí)現(xiàn)原理。首先,本文先談一下對(duì)threadlocal的理解,然后根據(jù) threadlocal類的源碼分析了其實(shí)現(xiàn)原理和使用需要注意的地方,最后給出了兩 個(gè)應(yīng)用場(chǎng)景。以下是木文目錄大綱:一. 對(duì) threadlocal 的理解二. 深入解析threadlocal類三. threadlocal的應(yīng)用場(chǎng)景若有不正之處請(qǐng)多多諒解,并歡迎批評(píng)指正。一對(duì)threadlocal的

2、理解threadlocal,很多地方叫做線程本地變量,也有些地方叫做線程本地存儲(chǔ),其 實(shí)意思差不多??赡芎芏嚯居讯贾纓hreadlocal為變量在每個(gè)線程屮都創(chuàng)建了 一個(gè)副本,那么每個(gè)線程可以訪問(wèn)自己內(nèi)部的副本變量。這句話從字面上看起來(lái)很容易理解,但是真正理解并不是那么容易。我們還是先來(lái)看-個(gè)例子:class connectionmanager private static connection connect 二 null;public static conneclion openconnection() if (cormect = null)connect = drivcrmanagcr

3、gctconncction();feturn connect;public static void closcconnection() if (connect!二null)connect. close ();假設(shè)有這樣一個(gè)數(shù)據(jù)庫(kù)鏈接管理類,這段代碼在單線程中使用是沒(méi)有任何問(wèn)題 的,但是如果在多線程中使用呢?很顯然,在多線程中使用會(huì)存在線程安全問(wèn)題: 第一,這里面的2個(gè)方法都沒(méi)有進(jìn)行同步,很可能在opcnconncction方法中會(huì) 多次創(chuàng)建connect;第二,由于connect是共享變量,那么必然在調(diào)用connect 的地方需要使用到同步來(lái)保障線程安全,因?yàn)楹芸赡芤粋€(gè)線程在使用connect

4、 進(jìn)行數(shù)據(jù)庫(kù)操作,而另外一個(gè)線程調(diào)用closeconnection關(guān)閉鏈接。所以出于線程安全的考慮,必須將這段代碼的兩個(gè)方法進(jìn)行同步處理,并且在調(diào) 用connect的地方需要進(jìn)行同步處理。這樣將會(huì)大大影響程序執(zhí)行效率,因?yàn)橐粋€(gè)線程在使用connect進(jìn)行數(shù)據(jù)庫(kù)操作 的時(shí)候,其他線程只有等待。那么大家來(lái)仔細(xì)分析一下這個(gè)問(wèn)題,這地方到底需不需要將connect變量進(jìn)行共 享?事實(shí)上,是不需耍的。假如每個(gè)線程中都有一個(gè)connect變量,各個(gè)線程之 間對(duì)connect變量的訪問(wèn)實(shí)際上是沒(méi)有依賴關(guān)系的,即一個(gè)線程不需要關(guān)心其他 線程是否對(duì)這個(gè)connect進(jìn)行了修改的。到這里,可能會(huì)有朋友想到,既然不

5、需要在線程z間共享這個(gè)變量,可以直接這 樣處理,在毎個(gè)需要使用數(shù)據(jù)庫(kù)連接的方法中具休使用時(shí)才創(chuàng)建數(shù)據(jù)庫(kù)鏈接,然 后在方法調(diào)用完畢再釋放這個(gè)連接。比如下面這樣:class connect!onmanager private connection connect 二 null;public connection openconnection() if (connect 二二 null)connect 二 drivcrmanagcr. gctconncction(); return connect;public void closcconncction() if (connect!二null)con

6、nect. close ();class dao public void insert() connectionmanager connectionmanager 二 new connectionmanager();connection connection = connectionmanager.openconnection();/使用connection進(jìn)彳亍操作conncctionmemagcr closcconncction(); 這樣處理確實(shí)也沒(méi)有任何問(wèn)題,由于每次都是在方法內(nèi)部創(chuàng)建的連接,那么線程 之間自然不存在線程安全問(wèn)題。但是這樣會(huì)有一個(gè)致命的影響:導(dǎo)致服務(wù)器壓力 非常大,并且

7、嚴(yán)重影響程序執(zhí)行性能。由于在方法中需要頻繁地開(kāi)啟和關(guān)閉數(shù)據(jù) 庫(kù)連接,這樣不盡嚴(yán)重影響程序執(zhí)行效率,述可能導(dǎo)致服務(wù)器壓力巨大。那么這種情況下使用threadlocal是再適合不過(guò)的了,因?yàn)閠hreadlocal在每個(gè) 線程中對(duì)該變量會(huì)創(chuàng)建一個(gè)副本,即毎個(gè)線程內(nèi)部都會(huì)有一個(gè)該變量,且在線程 內(nèi)部任何地方都可以使用,線程之間互不影響,這樣一來(lái)就不存在線程安全問(wèn)題, 也不會(huì)嚴(yán)重影響程序執(zhí)行性能。但是要注意,雖然threadlocal能夠解決上面說(shuō)的問(wèn)題,但是由于在每個(gè)線程中 都創(chuàng)建了副本,所以要考慮它對(duì)資源的消耗,比如內(nèi)存的占用會(huì)比不使用 threadlocal 要大。二.深入解析threadloca

8、l類在上面談到了對(duì)threadlocal的一些理解,那我們下面來(lái)看一下具體 threadlocal是如何實(shí)現(xiàn)的。先了解一下threadlocal類捉供的幾個(gè)方法:public t get () public void set(t value) public void remove() protected t initialvalue() get ()方法是用來(lái)獲取threadlocal在當(dāng)前線程中保存的變量副本,set ()用來(lái)設(shè) 置當(dāng)前線程中變量的副本,remove()用來(lái)移除當(dāng)前線程中變量的副本, initialvalue()是一個(gè)protected方法,一般是用來(lái)在使用吋進(jìn)行重寫(xiě)的,它是

9、 一個(gè)延遲加載方法,下面會(huì)詳細(xì)說(shuō)明。首先我們來(lái)看一 k threadlocal類是如何為每個(gè)線程創(chuàng)建一個(gè)變量的副本的。先看下get方法的實(shí)現(xiàn):第一句是取得當(dāng)前線程,然后通過(guò)getmeip(t)方法獲取到一個(gè)map, map的類型 為thrcadlocalmapo然后接著下面獲取到key, valuc鍵值對(duì),注意這里獲取鍵 值對(duì)傳進(jìn)去的是this,而不是當(dāng)前線程t。如果獲取成功,則返冋value值。如果map為空,則調(diào)用setlnitialvalue方法返冋value。我們上面的每一句來(lái)仔細(xì)分析: 首先看一卜'gctmap方法中做了什么: 可能大家沒(méi)冇想到的是,在getmap中,是調(diào)用當(dāng)

10、期線程t,返回當(dāng)前線程t屮 的一個(gè)成員變量threadlocalso那么我們繼續(xù)取thread類中取看一下成員變量lhreadlocals是什么:實(shí)際上就是一個(gè)threadlocalmap,這個(gè)類型是threadlocal類的一個(gè)內(nèi)部類, 我們繼續(xù)取看thrcadlocalmap的實(shí)現(xiàn):可以看到 threadlocalmap 的 entry 繼承了 weakreference,并口使用 threadlocal作為鍵值。然后再繼續(xù)看settnitialvalue方法的具體實(shí)現(xiàn):很容易了解,就是如果map不為空,就設(shè)置鍵值對(duì),為空,再創(chuàng)建map,看一下 createmap 的實(shí)現(xiàn):至此,可能大部分

11、朋友已經(jīng)明白了 threadlocal是如何為每個(gè)線程創(chuàng)建變量的副 本的:首先,在每個(gè)線程thread內(nèi)部有一個(gè)threadlocal. threadlocalmap類型的成員 變量threadlocals,這個(gè)threeidlocals就是用來(lái)存儲(chǔ)實(shí)際的變量副本的,鍵值 為當(dāng)前threadlocal變量,value為變量副本(即t類型的變量)。初始時(shí),在thread里而,threadlocals為空,當(dāng)通過(guò)threadlocal變量調(diào)用get () 方法或者set ()方法,就會(huì)對(duì)thread類中的threadlocals進(jìn)行初始化,并且以 當(dāng)前threadlocal變量為鍵值,以threa

12、dlocal要保存的副木變量為value,存 到 threadlocalso然后在當(dāng)前線程里而,如果要使用副本變量,就可以通過(guò)get方法在 threadlocals 里面查找。下面通過(guò)一個(gè)例子來(lái)證明通過(guò)threadlocal能達(dá)到在每個(gè)線程中創(chuàng)建變量副木 的效果:public class test threadlocal<long> longlocal 二 new thrcadlocal<long>();threadlocal<string> stringlocal = new threadlocal<string>();public void

13、set () ionglocal. set(thread, currentthread(). gettd(); str in glocal. sct( thread, curre ntthrceid() gctnamc ();public long getlongo return ionglocal. get();ijpublic string getstring() return stringlocal. get();public static void main(string args) throws interruptedexception final test test = new t

14、est ();test. set ();system, out. println(test. getlongo); system, out. println(test. getstring();thread thread1 二 new thread () public void run() test, set ();system, out. println(test. getlongo); system out. println(test. getstring(); ;thrcadl. start ();threadl. join();system, out. ptintln(test. ge

15、tlongo); system, out. println(test. getstring(); 這段代碼的輸出結(jié)果為:從這段代碼的輸出結(jié)果可以看出,在main線程中和thread 1線程中,longlocal 保存的副本值和stringlocal保存的副本值都不一樣。最后一次在main線程再 次打卬副本值是為了證明在main線程中和thread 1線程中的副本值確實(shí)是不同 的??偨Y(jié)一下:1)實(shí)際的通過(guò)thrcadlocal創(chuàng)建的副本是存儲(chǔ)在每個(gè)線程h己的threacllocals 中的;2)為何 threadlocals 的類型 threadlocalmap 的鍵值為 threadlocal

16、 對(duì)彖,因 為每個(gè)線程屮可有多個(gè)threadlocal變量,就像上面代碼屮的longlocal和 stringlocal;3)在進(jìn)行g(shù)et znij,必須先set,否則會(huì)報(bào)空指針異常;如果想在get之前不需要調(diào)用set就能正常訪問(wèn)的話,必須重寫(xiě)initialvalueo 方法。因?yàn)樵谏厦娴拇a分析過(guò)程屮,我們發(fā)現(xiàn)如果沒(méi)有先set的話,即在map屮查找 不到對(duì)應(yīng)的存儲(chǔ),則會(huì)通過(guò)調(diào)用settni tialvalue方法返回i,而在 sctlnitialvaluc 方法中,有 語(yǔ)句是 t value = initialvalueo ,而默認(rèn) 情況卜,initialvalue方法返回的是null??聪?/p>

17、面這個(gè)例子:public class test thrcadlocaklong> ionglocal 二 new thrcadlocaklong> (); threadlocakstring> stringlocal = new threadlocakstring>();public void set () ion glocal. set( thread, curre nt thread (). get td ();stringlocal. sct(thread, currentthread(). gctnamc();public long getlongo retur

18、n longlocal. get();public string getstringo return stringlocal. get ();public static void main(string args) throws intcrruptcdexccption final test test = new test ();system, out. println(test. getlongo);system, out. println(test. getstring();thread threadl 二 new thread()public void run() test, set (

19、);system, out. println(test. getlongo);system. out. println(test. getstring();thread 1. start ();thread 1. join();system, out. println(tcst. gctlong();system, out. println(test. getstring();在main線程中,沒(méi)有先set,直接get的話,運(yùn)行時(shí)會(huì)報(bào)空指針異常。但是如果改成卜面這段代碼,即重寫(xiě)了 initialvaluc方法:public class test threadlocal<long>

20、longlocal = new threadlocal<long> () protected long initialvalue() return thread, currentthread(). gettd();threadlocal<string> stringlocal = new threadlocal<string>(); protected string initialvalue() return thread.currentthread(). getname();public void set () 1onglocal. set(thread,

21、 currentthread(). gettd();strin glocal. set (thread, curr cn tthrcado. get name ();public long getlongo return longlocal. get();public string getstringo return stringlocal. get ();public static void nmin(string args) tbrows tnterruptedexception final test test 二 new test ();test, set ();system, out.

22、 println(test. getlongo);system. out. println(test. getstring();thread threadl = new thread ()public void run() test, set ();system. out. println(test. getlong();system, out. println(tcst. gctstring();threadl. start ();threadl. join();system, out. println(test. getlongo);system, out. println(test. g

23、etstringo);就可以直接不用先set而直接調(diào)用get to三.threadlocal的應(yīng)用場(chǎng)景最常見(jiàn)的threadlocal使用場(chǎng)景為用來(lái)解決 數(shù)據(jù)庫(kù)連接、session管理等。如:private static threadlocal<connection> connectionholder二 new thrcadlocakconncction>() public connection initialvalue() return drivermanager. getconnection(dbjjrl); "public static connection getconnectiono return connectionholder, get();下而這段代碼摘自:http:/www. itcyc. com/topic/103804private static final threadlocal th

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論