深入淺出ThreadLocal

          一、ThreadLocal概述

                 學(xué)習(xí)JDK中的類(lèi),首先看下JDK API對(duì)此類(lèi)的描述,描述如下:

          JDK API 寫(xiě)道
          該類(lèi)提供了線(xiàn)程局部 (thread-local) 變量。這些變量不同于它們的普通對(duì)應(yīng)物,因?yàn)樵L問(wèn)某個(gè)變量(通過(guò)其 get 或 set 方法)的每個(gè)線(xiàn)程都有自己的局部變量,它獨(dú)立于變量的初始化副本。ThreadLocal 實(shí)例通常是類(lèi)中的 private static 字段,它們希望將狀態(tài)與某一個(gè)線(xiàn)程(例如,用戶(hù) ID 或事務(wù) ID)相關(guān)聯(lián)。 

              API表達(dá)了下面幾種觀點(diǎn):

          1、ThreadLocal不是線(xiàn)程,是線(xiàn)程的一個(gè)變量,你可以先簡(jiǎn)單理解為線(xiàn)程類(lèi)的屬性變量。

          2、ThreadLocal 在類(lèi)中通常定義為靜態(tài)類(lèi)變量。

          3、每個(gè)線(xiàn)程有自己的一個(gè)ThreadLocal,它是變量的一個(gè)‘拷貝’,修改它不影響其他線(xiàn)程。


              既然定義為類(lèi)變量,為何為每個(gè)線(xiàn)程維護(hù)一個(gè)副本(姑且成為‘拷貝’容易理解),讓每個(gè)線(xiàn)程獨(dú)立訪問(wèn)?多線(xiàn)程編程的經(jīng)驗(yàn)告訴我們,對(duì)于線(xiàn)程共享資源(你可以理解為屬性),資源是否被所有線(xiàn)程共享,也就是說(shuō)這個(gè)資源被一個(gè)線(xiàn)程修改是否影響另一個(gè)線(xiàn)程的運(yùn)行,如果影響我們需要使用synchronized同步,讓線(xiàn)程順序訪問(wèn)。


             ThreadLocal適用于資源共享但不需要維護(hù)狀態(tài)的情況,也就是一個(gè)線(xiàn)程對(duì)資源的修改,不影響另一個(gè)線(xiàn)程的運(yùn)行;這種設(shè)計(jì)是‘空間換時(shí)間’,synchronized順序執(zhí)行是‘時(shí)間換取空間’


          二、ThreadLocal方法介紹



           T get() 
                    返回此線(xiàn)程局部變量的當(dāng)前線(xiàn)程副本中的值。
          protected  T initialValue() 
                    返回此線(xiàn)程局部變量的當(dāng)前線(xiàn)程的“初始值”。
           void remove() 
                    移除此線(xiàn)程局部變量當(dāng)前線(xiàn)程的值。
           void set(T value) 
                    將此線(xiàn)程局部變量的當(dāng)前線(xiàn)程副本中的值設(shè)置為指定值。


          三、深入源碼

              ThreadLocal有一個(gè)ThreadLocalMap靜態(tài)內(nèi)部類(lèi),你可以簡(jiǎn)單理解為一個(gè)MAP,這個(gè)‘Map’為每個(gè)線(xiàn)程復(fù)制一個(gè)變量的‘拷貝’存儲(chǔ)其中。

              當(dāng)線(xiàn)程調(diào)用ThreadLocal.get()方法獲取變量時(shí),首先獲取當(dāng)前線(xiàn)程引用,以此為key去獲取響應(yīng)的ThreadLocalMap,如果此‘Map’不存在則初始化一個(gè),否則返回其中的變量,代碼如下:


           public T get() {
          Thread t = Thread.currentThread();
          ThreadLocalMap map = getMap(t);
          if (map != null) {
          ThreadLocalMap.Entry e = map.getEntry(this);
          if (e != null)
          return (T)e.value;
          }
          return setInitialValue();
          }

              調(diào)用get方法如果此Map不存在首先初始化,創(chuàng)建此map,將線(xiàn)程為key,初始化的vlaue存入其中,注意此處的initialValue,我們可以覆蓋此方法,在首次調(diào)用時(shí)初始化一個(gè)適當(dāng)?shù)闹怠etInitialValue代碼如下:

              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;
          }


              set方法相對(duì)比較簡(jiǎn)單如果理解以上倆個(gè)方法,獲取當(dāng)前線(xiàn)程的引用,從map中獲取該線(xiàn)程對(duì)應(yīng)的map,如果map存在更新緩存值,否則創(chuàng)建并存儲(chǔ),代碼如下:

              public void set(T value) {
          Thread t = Thread.currentThread();
          ThreadLocalMap map = getMap(t);
          if (map != null)
          map.set(this, value);
          else
          createMap(t, value);
          }


              對(duì)于ThreadLocal在何處存儲(chǔ)變量副本,我們看getMap方法:獲取的是當(dāng)前線(xiàn)程的ThreadLocal類(lèi)型的threadLocals屬性。顯然變量副本存儲(chǔ)在每一個(gè)線(xiàn)程中。


          /**
          * 獲取線(xiàn)程的ThreadLocalMap 屬性實(shí)例
          */
          ThreadLocalMap getMap(Thread t) {
          return t.threadLocals;
          }


              上面我們知道變量副本存放于何處,這里我們簡(jiǎn)單說(shuō)下如何被java的垃圾收集機(jī)制收集,當(dāng)我們不在使用是調(diào)用set(null),此時(shí)不在將引用指向該‘map’,而線(xiàn)程退出時(shí)會(huì)執(zhí)行資源回收操作,將申請(qǐng)的資源進(jìn)行回收,其實(shí)就是將屬性的引用設(shè)置為null。這時(shí)已經(jīng)不在有任何引用指向該map,故而會(huì)被垃圾收集。


           四、ThreadLocal應(yīng)用示例


                在我的另一篇文章,對(duì)ThreadLocal的使用做了一個(gè)實(shí)例,此示例也可以用作生產(chǎn)環(huán)境,請(qǐng)參見(jiàn):http://ari.iteye.com/blog/757641



          如有問(wèn)題請(qǐng)留言討論,謝謝

          posted on 2011-05-10 21:02 空白 閱讀(411) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Java

          <2011年5月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          導(dǎo)航

          統(tǒng)計(jì)

          常用鏈接

          留言簿(1)

          隨筆分類(lèi)(15)

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 扬州市| 宣威市| 会同县| 广平县| 长阳| 道孚县| 加查县| 彭泽县| 广安市| 三河市| 山西省| 利辛县| 防城港市| 苏尼特左旗| 虎林市| 鹰潭市| 连城县| 嘉祥县| 化州市| 彭州市| 桑植县| 昌乐县| 霸州市| 报价| 乌恰县| 九龙县| 竹溪县| 五寨县| 河池市| 邵武市| 天水市| 北海市| 闽侯县| 丁青县| 无为县| 上林县| 甘肃省| 明星| 安泽县| 普兰店市| 罗定市|