Java多線程基礎總結四:ThreadLocal

來源:互聯網
上載者:User

說到ThreadLocal,首先說說這個類的命名。直觀上看好像是個Thread的什麼親戚,但其實它想表達的意思是執行緒區域變數,也就是說每 個線程自己的變數。它作為一個JDK5以後支援範型的類,主要是想利用範型把非安全執行緒的共用變數,封裝成綁定線程的安全不共用變數。 這樣的解釋我想我們多半能猜出它的實現思路:把一個共用變數在每個線程使用時,初始化一個副本,並且和線程綁定。以後所有的線程對 共用變數的操作都是對線程內部那個副本,完全的線程內部變數的操作。

要實現這樣功能類的設計,主要技術點是要能把副本和線程綁定映射,程式可以安全尋找到當前線程的副本,修改後安全的綁定給線程 。所以我們想到了Map的儲存結構,ThreadLocal內部就是使用了安全執行緒的Map形式的儲存把currentThread和變數副本一一映射。

既然要把共用的變成不共用的,那麼就要變數滿足一個情境:變數的狀態不需要共用。例如無狀態的bean在多線程之間是安全的,因為 線程之間不需要同步bean的狀態,用了就走(很不負責啊),想用就用。但是對於有狀態的bean線上程之間則必須小心,線程A剛看到狀態 是a,正想利用a做事情,線程B把bean的狀態改為了b,結果做了不該做的。但是如果有狀態的bean不需要共用狀態,每個線程看到狀態a或 者b都可以做出自己的行為,這種情況下不同步的選擇就是ThreadLocal了。

利用ThreadLocal的優勢就在於根本不用擔心有狀態的bean為了狀態的一致而犧牲效能,去使用synchronized限制只有一個線程在同一時 間做出關於bean狀態的行為。而是多個線程同時根據自己持有的bean的副本的狀態做出行為,這樣的轉變對於並發的支援是那麼的不可思議 。例如一個 Dao內有個Connection的屬性,當多個線程使用Dao的同一個執行個體時,問題就來了:多個線程用一個Connection,而且它還是有 串連,關閉等等的狀態轉變的,我們很敏感的想到這個屬性不安全!再看這個屬性,其實它是多麼的想告訴線程哥哥們:我的這些狀態根本 就不想共用,不要因為我的狀態而不敢一起追求。線程哥哥們也鬱悶:你要是有多胞胎姐妹該多好啊!這時候ThreadLocal大哥過來說:小 菜,我來搞定!你們這些線程一人一個 Connection,你想關就關,想串連就串連,再也不用抱怨說它把你的串連關了。這樣Dao的執行個體再也 不用因為自己有個不安全的屬性而自卑了。當然 ThreadLocal的思路雖然是很好的,但是官方的說法是最初的實現效能並不好,隨著Map結 構和Thread.currentThread的改進,效能較之synchronized才有了明顯的優勢。所以要是使用的是JDK1.2,JDK1.3等等,也不要妄想麻雀變 鳳凰...

再看ThreadLocal和synchronized的本質。前者不在乎多佔點空間,但是絕對的忍受不了等待;後者對等待無所謂,但是就是不喜歡浪費 空間。這也反映出了演算法的一個規律:通常是使用情境決定時間和空間的比例,既省時又省地的演算法多數情況下只存在於幻想之中。下面寫 個簡單的例子解釋一下,不過個人覺得設計的例子不太好,以後有實際的啟發再替換吧。

Java代碼

import java.util.concurrent.atomic.AtomicInteger;

/** 
  * User: yanxuxin 
  * Date: Dec 14, 2009 
  * Time: 9:26:41 PM 
  */
public class ThreadLocalSample extends Thread {
   private OperationSample2 operationSample;

   public ThreadLocalSample(OperationSample2 operationSample) {
     this.operationSample = operationSample;
   }

   @Override
   public void run() {
     operationSample.printAndIncrementNum();
   }

   public static void main(String[] args) {

     final OperationSample2 operation = new OperationSample2();//The shared Object for threads.

     for (int i = 0; i < 5; i++) {
       new ThreadLocalSample(operation).start();
     }
   }
}

class OperationSample {
   private int num;

   //public synchronized void printAndIncrementNum() {
   public void printAndIncrementNum() {
     for (int i = 0; i < 2; i++) {
       System.out.println(Thread.currentThread().getName() + "[id=" + num + "]");
       num += 10;
     }
   }
}

class OperationSample2 {

   private static ThreadLocal<Integer> threadArg = new ThreadLocal<Integer>() {
     @Override
     protected Integer initialValue() {
       return 0;
     }
   };

   public void printAndIncrementNum() {
     for (int i = 0; i < 2; i++) {
       int num = threadArg.get();
       threadArg.set(num + 10);
       System.out.println(Thread.currentThread().getName() + "[id=" + num + "]");
     }
   }
}

class OperationSample3 {

   private static final AtomicInteger uniqueId = new AtomicInteger(0);
   private static ThreadLocal<Integer> threadArg = new ThreadLocal<Integer>() {
     @Override
     protected Integer initialValue() {
       return uniqueId.getAndIncrement();
     }
   };

   public void printAndIncrementNum() {
     for (int i = 0; i < 2; i++) {
       int num = threadArg.get();
       threadArg.set(num + 10);
       System.out.println(Thread.currentThread().getName() + "[id=" + num + "]");
     }
   }
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.