泰仔在線

          java學(xué)習(xí),心情日記,繽紛時刻
          posts - 100, comments - 34, trackbacks - 0, articles - 0

          ThreadLocal的使用說明

          Posted on 2007-04-12 09:44 泰仔在線 閱讀(372) 評論(0)  編輯  收藏 所屬分類: Java 相關(guān)
          早在Java 1.2推出之時,Java平臺中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序時提供了一種新的選擇。使用這個工具類可以很簡潔地編寫出優(yōu)美的多線程程序,雖然ThreadLocal非常有用,但是似乎現(xiàn)在了解它、使用它的朋友還不多。

            ThreadLocal是什么

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

            ThreadLocal的設(shè)計

            首先看看ThreadLocal的接口:

            Object get() ; // 返回當(dāng)前線程的線程局部變量副本 
                   protected Object initialValue(); // 返回該線程局部變量的當(dāng)前線程的初始值
                   void set(Object value); // 設(shè)置當(dāng)前線程的線程局部變量副本的值

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

          protected Object initialValue() { return null; }

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

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

            當(dāng)然,這并不是一個工業(yè)強(qiáng)度的實現(xiàn),但JDK中的ThreadLocal的實現(xiàn)總體思路也類似于此。

            ThreadLocal的使用

            如果希望線程局部變量初始化其它值,那么需要自己實現(xiàn)ThreadLocal的子類并重寫該方法,通常使用一個內(nèi)部匿名類對ThreadLocal進(jìn)行子類化,比如下面的例子,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的,所以在需要獲取當(dāng)前線程的序號時,簡單地調(diào)用:

          int serial = SerialNum.get();

            即可。

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

            ThreadLocal與其它同步機(jī)制的比較

            ThreadLocal和其它同步機(jī)制相比有什么優(yōu)勢呢?ThreadLocal和其它所有的同步機(jī)制都是為了解決多線程中的對同一變量的訪問沖突,在普通的同步機(jī)制中,是通過對象加鎖來實現(xiàn)多個線程對同一變量的安全訪問的。這時該變量是多個線程共享的,使用這種同步機(jī)制需要很細(xì)致地分析在什么時候?qū)ψ兞窟M(jìn)行讀寫,什么時候需要鎖定某個對象,什么時候釋放該對象的鎖等等很多。所有這些都是因為多個線程共享了資源造成的。ThreadLocal就從另一個角度來解決多線程的并發(fā)訪問,ThreadLocal會為每一個線程維護(hù)一個和該線程綁定的變量的副本,從而隔離了多個線程的數(shù)據(jù),每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進(jìn)行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的整個變量封裝進(jìn)ThreadLocal,或者把該對象的特定于線程的狀態(tài)封裝進(jìn)ThreadLocal。

            由于ThreadLocal中可以持有任何類型的對象,所以使用ThreadLocal get當(dāng)前線程的值是需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換。但隨著新的Java版本(1.5)將模版的引入,新的支持模版參數(shù)的ThreadLocal<T>類將從中受益。也可以減少強(qiáng)制類型轉(zhuǎn)換,并將一些錯誤檢查提前到了編譯期,將一定程度地簡化ThreadLocal的使用。

            總結(jié)

            當(dāng)然ThreadLocal并不能替代同步機(jī)制,兩者面向的問題領(lǐng)域不同。同步機(jī)制是為了同步多個線程對相同資源的并發(fā)訪問,是為了多個線程之間進(jìn)行通信的有效方式;而ThreadLocal是隔離多個線程的數(shù)據(jù)共享,從根本上就不在多個線程之間共享資源(變量),這樣當(dāng)然不需要對多個線程進(jìn)行同步了。所以,如果你需要進(jìn)行多個線程之間進(jìn)行通信,則使用同步機(jī)制;如果需要隔離多個線程之間的共享沖突,可以使用ThreadLocal,這將極大地簡化你的程序,使程序更加易讀、簡潔。

          引自:http://junhao.wacky.cn/threas,606459.html
          主站蜘蛛池模板: 化德县| 尖扎县| 阜平县| 简阳市| 聂荣县| 阿克苏市| 新龙县| 木兰县| 普格县| 华亭县| 临汾市| 衡山县| 汉源县| 攀枝花市| 峨眉山市| 肥西县| 宁德市| 丰都县| 类乌齐县| 板桥市| 潞城市| 贵溪市| 兰西县| 芦溪县| 安达市| 乳源| 富川| 富顺县| 临汾市| 横山县| 周宁县| 朝阳县| 吴旗县| 翁源县| 阜城县| 边坝县| 玉屏| 德化县| 盐亭县| 定结县| 综艺|