隨筆-14  評(píng)論-142  文章-0  trackbacks-0


          ThreadLocal的設(shè)計(jì)與使用






            早在Java 1.2推出之時(shí),Java平臺(tái)中就引入了一個(gè)新的支持:java.lang.ThreadLocal,給我們?cè)诰帉懚嗑€程程序時(shí)提供了一種新的選擇。使用這個(gè)工具類可以很簡(jiǎn)潔地編寫出優(yōu)美的多線程程序,雖然ThreadLocal非常有用,但是似乎現(xiàn)在了解它、使用它的朋友還不多。

            ThreadLocal是什么

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

            ThreadLocal的設(shè)計(jì)

            首先看看ThreadLocal的接口:

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

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





          protected Object initialValue() { return null; }

            ThreadLocal是如何做到為每一個(gè)線程維護(hù)變量的副本的呢?其實(shí)實(shí)現(xiàn)的思路很簡(jiǎn)單,在ThreadLocal類中有一個(gè)Map,用于存儲(chǔ)每一個(gè)線程的變量的副本。比如下面的示例實(shí)現(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)然,這并不是一個(gè)工業(yè)強(qiáng)度的實(shí)現(xiàn),但JDK中的ThreadLocal的實(shí)現(xiàn)總體思路也類似于此。

            ThreadLocal的使用

            如果希望線程局部變量初始化其它值,那么需要自己實(shí)現(xiàn)ThreadLocal的子類并重寫該方法,通常使用一個(gè)內(nèi)部匿名類對(duì)ThreadLocal進(jìn)行子類化,比如下面的例子,SerialNum類為每一個(gè)類分配一個(gè)序號(hào):





          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類的使用將非常地簡(jiǎn)單,因?yàn)間et()方法是static的,所以在需要獲取當(dāng)前線程的序號(hào)時(shí),簡(jiǎn)單地調(diào)用:





          int serial = SerialNum.get();

            即可。

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

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

            ThreadLocal和其它同步機(jī)制相比有什么優(yōu)勢(shì)呢?ThreadLocal和其它所有的同步機(jī)制都是為了解決多線程中的對(duì)同一變量


          posted on 2006-10-04 06:47 liulang 閱讀(601) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 武陟县| 东方市| 沧州市| 镇平县| 兴隆县| 丹棱县| 天峻县| 故城县| 微山县| 托克逊县| 张家口市| 东阿县| 武冈市| 岳普湖县| 马鞍山市| 扬中市| 康平县| 鸡东县| 卢龙县| 贺兰县| 黄平县| 陆河县| 江阴市| 嘉峪关市| 略阳县| 鹰潭市| 佛学| 上栗县| 武清区| 灵川县| 普兰店市| 广南县| 甘南县| 革吉县| 阳原县| 邹城市| 铜梁县| 昭苏县| 谢通门县| 彝良县| 深州市|