posts - 73,  comments - 55,  trackbacks - 0

          早在Java 1.2推出之時,Java平臺中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序時提供了一種新的選擇。使用這個工具類可以很簡潔地編寫出優美的多線程程序,雖然ThreadLocal非常有用,但是似乎現在了解它、使用它的朋友還不多。

          ThreadLocal是什么

          ThreadLocal并非是一個線程的本地實現版本,它并不是一個Thread,而是thread local variable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。從線程的角度看,就好像每一個線程都完全擁有該變量。線程局部變量并不是Java的新發明,在其它的一些語言編譯器實現(如IBM XL FORTRAN)中,它在語言的層次提供了直接的支持。因為Java中沒有提供在語言層次的直接支持,而是提供了一個ThreadLocal的類來提供支持,所以,在Java中編寫線程局部變量的代碼相對比較笨拙,這也許是線程局部變量沒有在Java中得到很好的普及的一個原因吧。

          ThreadLocal的設計

          首先看看ThreadLocal的接口:

          Object get() ;

          // 返回當前線程的線程局部變量副本 protected Object initialValue(); // 返回該線程局部變量的當前線程的初始值

          void set(Object value);

          // 設置當前線程的線程局部變量副本的值

          ThreadLocal有3個方法,其中值得注意的是initialValue(),該方法是一個protected的方法,顯然是為了子類重寫而特意實現的。該方法返回當前線程在該線程局部變量的初始值,這個方法是一個延遲調用方法,在一個線程第1次調用get()或者set(Object)時才執行,并且僅執行1次。ThreadLocal中的確實實現直接返回一個null:

          protected Object initialValue() { return null; }

          ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用于存儲每一個線程的變量的副本。比如下面的示例實現:


          public class ThreadLocal
          {
          private Map values = Collections.synchronizedMap(new HashMap());
          public Object get()
          {
          Thread curThread = Thread.currentThread();
          Object o = values.get(curThread);
          if (o == null && !values.containsKey(curThread))
          {
          o = initialValue();
          values.put(curThread, o);
          }
          return o;
          }

          public void set(Object newValue)
          {
          values.put(Thread.currentThread(), newValue);
          }

          public Object initialValue()
          {
          return null;
          }
          }

          ?


          當然,這并不是一個工業強度的實現,但JDK中的ThreadLocal的實現總體思路也類似于此。

          ThreadLocal的使用

          如果希望線程局部變量初始化其它值,那么需要自己實現ThreadLocal的子類并重寫該方法,通常使用一個內部匿名類對ThreadLocal進行子類化,比如下面的例子,SerialNum類為每一個類分配一個序號


          public class SerialNum
          {
          // The next serial number to be assigned

          private static int nextSerialNum = 0;

          private static ThreadLocal serialNum = new ThreadLocal()
          {
          protected synchronized Object initialValue()
          {
          return new Integer(nextSerialNum++);
          }
          };


          public static int get()
          {
          return ((Integer) (serialNum.get())).intValue();
          }

          }

          ?


          SerialNum類的使用將非常地簡單,因為get()方法是static的,所以在需要獲取當前線程的序號時,簡單地調用:

          int serial = SerialNum.get();

          即可。

          在線程是活動的并且ThreadLocal對象是可訪問的時,該線程就持有一個到該線程局部變量副本的隱含引用,當該線程運行結束后,該線程擁有的所以線程局部變量的副本都將失效,并等待垃圾收集器收集。

          ThreadLocal與其它同步機制的比較

          ThreadLocal和其它同步機制相比有什么優勢呢?ThreadLocal和其它所有的同步機制都是為了解決多線程中的對同一變量的訪問沖突,在普通的同步機制中,是通過對象加鎖來實現多個線程對同一變量的安全訪問的。這時該變量是多個線程共享的,使用這種同步機制需要很細致地分析在什么時候對變量進行讀寫,什么時候需要鎖定某個對象,什么時候釋放該對象的鎖等等很多。所有這些都是因為多個線程共享了資源造成的。ThreadLocal就從另一個角度來解決多線程的并發訪問,ThreadLocal會為每一個線程維護一個和該線程綁定的變量的副本,從而隔離了多個線程的數據,每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量

          posted on 2006-12-27 21:37 保爾任 閱讀(340) 評論(0)  編輯  收藏 所屬分類: J2SE

          <2006年12月>
          262728293012
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(4)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 旅游| 佳木斯市| 濮阳市| 云霄县| 安顺市| 尼勒克县| 泊头市| 辽源市| 吐鲁番市| 噶尔县| 集安市| 勃利县| 巴林左旗| 建平县| 贡山| 徐闻县| 深泽县| 海原县| 安丘市| 延边| 胶南市| 车险| 锡林浩特市| 特克斯县| 巴南区| 台江县| 静乐县| 宜阳县| 罗定市| 太原市| 临猗县| 星座| 读书| 中西区| 鲁甸县| 文昌市| 宁海县| 怀远县| 张北县| 中西区| 临武县|