posts - 1,  comments - 25,  trackbacks - 0

              ThreadLocal的核心思想很簡(jiǎn)單:為每個(gè)獨(dú)立的線程提供一個(gè)變量的副本。

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

              為了加深對(duì)ThreadLocal的理解,下面我使用一個(gè)例子來(lái)演示ThreadLocal如何隔離線程間的變量訪問(wèn)和修改:

          【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()
                          + " 獲取到的序列號(hào)是" + mySerialNum);
                  System.out.println("線程 " + Thread.currentThread().getName()
                          + " 修改了序列號(hào)為" + (mySerialNum * 3));
                  setSerialNum(mySerialNum * 3);
                  System.out.println("線程 " + Thread.currentThread().getName()
                          + " 再次獲得的序列號(hào)是" + getSerialNum());
              }

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

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

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

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

              為什么會(huì)這樣呢?明明serialNum是靜態(tài)變量啊?其實(shí)我們只需要看看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)部維護(hù)了一個(gè)Map,將變量的值和線程綁定起來(lái),get/set方法都是對(duì)該線程對(duì)應(yīng)的value進(jìn)行操作,所以不會(huì)影響到其它線程。
          posted on 2010-12-09 19:27 Daniel 閱讀(209) 評(píng)論(0)  編輯  收藏 所屬分類: CoreJava
          <2025年8月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          31123456

          常用鏈接

          留言簿(3)

          隨筆檔案

          文章分類

          文章檔案

          相冊(cè)

          搜索

          •  

          最新評(píng)論

          主站蜘蛛池模板: 沙湾县| 随州市| 黎平县| 苗栗县| 静宁县| 宁都县| 肃宁县| 天等县| 黎平县| 昌图县| 九江市| 泌阳县| 得荣县| 五原县| 盱眙县| 淮滨县| 威信县| 山阴县| 屏东市| 平山县| 紫阳县| 井研县| 衡南县| 额济纳旗| 宝兴县| 贵港市| 晴隆县| 资中县| 青海省| 文水县| 黄山市| 化隆| 湛江市| 喀喇沁旗| 丹凤县| 五原县| 宜丰县| 富民县| 周至县| 科尔| 锡林郭勒盟|