程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> JAVA編程入門知識 >> Java中ThreadLocal的設計與使用

Java中ThreadLocal的設計與使用

編輯:JAVA編程入門知識
  早在Java 1.2推出之時,Java平台中就引入了一個新的支持:java.lang.ThreadLocal,給我們在編寫多線程程序時提供了一種新的選擇。使用這個工具類可以很簡潔地編寫出美麗的多線程程序,雖然ThreadLocal非常有用,但是似乎現在了解它、使用它的朋友還不多。
  
   <!-- frame contents --> <!-- /frame contents -->    ThreadLocal是什麼
  
   ThreadLocal是什麼呢?其實ThreadLocal並非是一個線程的本地實現版本,它並不是一個Thread,而是thread local variable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。線程局部變量(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本沖突。從線程的角度看,就似乎每一個線程都完全擁有該變量。線程局部變量並不是Java的新發明,在其它的一些語言編譯器實現(如IBM XL FORTRAN)中,它在語言的層次提供了直接的支持。因為Java中沒有提供在語言層次的直接支持,而是提供了一個ThreadLocal的類來提供支持,所以,在Java中編寫線程局部變量的代碼相對比較笨拙,這也許是線程局部變量沒有在Java中得到很好的普及的一個原因吧。
  
   ThreadLocal的設計
  
   首先看看ThreadLocal的接口:
  
    Object get() ; // 返回當前線程的線程局部變量副本 protected Object initialValue(); // 返回該線程局部變量的當前線程的初始值
    void set(Object value); // 設置當前線程的線程局部變量副本的值
  
   ThreadLocal有3個方法,其中值得注重的是initialValue(),該方法是一個protected的方法,顯然是為了子類重寫而特意實現的。該方法返回當前線程在該線程局部變量的初始值,這個方法是一個延遲調用方法,在一個線程第1次調用get()或者set(Object)時才執行,並且僅執行1次。ThreadLocal中的確實實現直接返回一個null:
  
   protected Object initialValue() { return null; }
  ThreadLocal是如何做到為每一個線程維護變量的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用於存儲每一個線程的變量的副本。比如下面的示例實現:
  
   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;
    }
  }
  當然,這並不是一個工業強度的實現,但JDK中的ThreadLocal的實現總體思路也類似於此。
  
   ThreadLocal的使用
  
   假如希望線程局部變量初始化其它值,那麼需要自己實現ThreadLocal的子類並重寫該方法,通常使用一個內部匿名類對ThreadLocal進行子類化,比如下面的例子,SerialNum類為每一個類分配一個序號:
  
   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類的使用將非常地簡單,因為get()方法是static的,所以在需要獲取當前線程的序號時,簡單地調用:
  
 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved