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

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

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

              為什么會這樣呢?明明serialNum是靜態變量啊?其實我們只需要看看ThreadLocal的內部構造就知道了:

          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在內部維護了一個Map,將變量的值和線程綁定起來,get/set方法都是對該線程對應的value進行操作,所以不會影響到其它線程。
          posted on 2010-12-09 19:27 Daniel 閱讀(207) 評論(0)  編輯  收藏 所屬分類: CoreJava
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(3)

          隨筆檔案

          文章分類

          文章檔案

          相冊

          搜索

          •  

          最新評論

          主站蜘蛛池模板: 汕尾市| 白水县| 大冶市| 贺州市| 巴彦淖尔市| 安图县| 澄城县| 云林县| 天台县| 漯河市| 勐海县| 靖州| 阿巴嘎旗| 济南市| 荔浦县| 信宜市| 鄢陵县| 安义县| 阿鲁科尔沁旗| 新化县| 山东省| 双辽市| 巨鹿县| 洛南县| 新干县| 昌黎县| 申扎县| 万荣县| 宝兴县| 五大连池市| 乌海市| 九江县| 平果县| 黄陵县| 襄汾县| 无锡市| 商丘市| 东方市| 祁东县| 荔浦县| 绥阳县|