posts - 1,  comments - 25,  trackbacks - 0

              ThreadLocal的核心思想很簡單:為每個獨立的線程提供一個變量的副本。

              ThreadLocal則使用了“拷貝副本”的方式,人人有份,你用你的,我用我的,大家互不影響,是“以空間換時間”。每個線程修改變量時,實際上修改的是變量的副本,不怕影響到其它線程。

              為了加深對ThreadLocal的理解,下面我使用一個例子來演示ThreadLocal如何隔離線程間的變量訪問和修改:

          【1】SerialNum類

          package example.thread.threadLocal;

          public class SerialNum {

              private static int nextSerialNum = 1;

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

              public static int get() {
                  return ((Integer) (serialNum.get())).intValue();
              }
              
              @SuppressWarnings("unchecked")
              public static void set(Integer newSerial){
                  serialNum.set(newSerial);
              }
          }

          【2】GetSerialNumThread
          package example.thread.threadLocal;

          public class GetSerialNumThread implements Runnable {

              public static void main(String args[]) {

                  GetSerialNumThread serialNumGetter = new GetSerialNumThread();
                  Thread t1 = new Thread(serialNumGetter, "Thread A");
                  Thread t2 = new Thread(serialNumGetter, "Thread B");
                  t1.start();
                  try {
                      t1.join();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }    
                  t2.start();            
              }

              public void run() {
                  int mySerialNum = getSerialNum();
                  System.out.println("線程 " + Thread.currentThread().getName()
                          + " 獲取到的序列號是" + mySerialNum);
                  System.out.println("線程 " + Thread.currentThread().getName()
                          + " 修改了序列號為" + (mySerialNum * 3));
                  setSerialNum(mySerialNum * 3);
                  System.out.println("線程 " + Thread.currentThread().getName()
                          + " 再次獲得的序列號是" + getSerialNum());
              }

              private int getSerialNum() {
                  return SerialNum.get();
              }

              private void setSerialNum(int newSerialNum) {
                  SerialNum.set(new Integer(newSerialNum));
              }
          }

          運行的結(jié)果如下:
          線程 Thread A 獲取到的序列號是1
          線程 Thread A 修改了序列號為3
          線程 Thread A 再次獲得的序列號是3
          線程 Thread B 獲取到的序列號是2
          線程 Thread B 修改了序列號為6
          線程 Thread B 再次獲得的序列號是6

              可見第一個線程在調(diào)用SerialNum.set(int)方法修改static變量時,其實修改的是它自己的副本,而不是修改本地變量,第二個線程在初始化的時候拿到的序列號是2而不是7。

              為什么會這樣呢?明明serialNum是靜態(tài)變量???其實我們只需要看看ThreadLocal的內(nèi)部構(gòu)造就知道了:

          A. ThreadLocal的get()方法:
           /**
               * Returns the value in the current thread's copy of this thread-local
               * variable.  Creates and initializes the copy if this is the first time
               * the thread has called this method.
               *
               * @return the current thread's value of this thread-local
               */
              public T get() {
                  Thread t = Thread.currentThread();
                  ThreadLocalMap map = getMap(t);
                  if (map != null)
                      return (T)map.get(this);

                  // Maps are constructed lazily.  if the map for this thread
                  // doesn't exist, create it, with this ThreadLocal and its
                  // initial value as its only entry.
                  T value = initialValue();
                  createMap(t, value);
                  return value;
              }

          B. ThreadLocal的set()方法:
          /**
               * Sets the current thread's copy of this thread-local variable
               * to the specified value.  Many applications will have no need for
               * this functionality, relying solely on the {@link #initialValue}
               * method to set the values of thread-locals.
               *
               * @param value the value to be stored in the current threads' copy of
               *        this thread-local.
               */
              public void set(T value) {
                  Thread t = Thread.currentThread();
                  ThreadLocalMap map = getMap(t);
                  if (map != null)
                      map.set(this, value);
                  else
                      createMap(t, value);
              }

              可以看到ThreadLocal在內(nèi)部維護了一個Map,將變量的值和線程綁定起來,get/set方法都是對該線程對應(yīng)的value進行操作,所以不會影響到其它線程。
          posted on 2010-12-09 19:27 Daniel 閱讀(209) 評論(0)  編輯  收藏 所屬分類: CoreJava
          <2025年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(3)

          隨筆檔案

          文章分類

          文章檔案

          相冊

          搜索

          •  

          最新評論

          主站蜘蛛池模板: 伊春市| 云霄县| 康乐县| 黑河市| 女性| 喀喇沁旗| 乌苏市| 靖西县| 遂宁市| 广平县| 奈曼旗| 宜章县| 敦煌市| 台北县| 太仆寺旗| 方正县| 綦江县| 琼海市| 三亚市| 云和县| 万全县| 玛沁县| 河池市| 拜泉县| 区。| 全州县| 东阿县| 新晃| 柳州市| 河北省| 夏津县| 白山市| 遵义市| 杨浦区| 侯马市| 福建省| 洱源县| 玉树县| 渭源县| 庆安县| 商城县|