《Java併發性和多執行緒介紹》-Java TheadLocal
Java中的ThreadLocal類可以讓你建立的變數只被同一個執行緒進行讀和寫操作。因此,儘管有兩個執行緒同時執行一段相同的程式碼,而且這段程式碼又有一個指向同一個ThreadLocal變數的引用,但是這兩個執行緒依然不能看到彼此的ThreadLocal變數域。
1、建立一個ThreadLocal物件
如下所示,建立一個ThreadLocal變數:
private ThreadLocal myThreadLocal = new ThreadLocal();
你例項化了一個ThreadLocal物件。每個執行緒僅需要例項化一次即可。雖然不同的執行緒執行同一段程式碼時,訪問同一個ThreadLocal變數,但是每個執行緒只能看到私有的ThreadLocal例項。所以不同的執行緒在給ThreadLocal物件設定不同的值時,他們也不能看到彼此的修改。
2、訪問ThreadLocal物件
一旦建立了一個ThreadLocal物件,你就可以通過以下方式來儲存此物件的值:
myThreadLocal.set("A thread local value");
也可以直接讀取一個ThreadLocal物件的值:
String threadLocalValue = (String) myThreadLocal.get();
get()方法會返回一個Object物件,而set()方法則依賴一個Object物件引數。
3、ThreadLocal泛型
為了使get()方法返回值不用做強制型別轉換,通常可以建立一個泛型化的ThreadLocal物件。以下就是一個泛型化的ThreadLocal示例:
private ThreadLocal myThreadLocal1 = new ThreadLocal<String>();
現在你可以儲存一個字串到ThreadLocal例項裡,此外,當你從此ThreadLocal例項中獲取值的時候,就不必要做強制型別轉換。
myThreadLocal1.set("Hello ThreadLocal"); String threadLocalValues = myThreadLocal.get();
4、初始化ThreadLocal
由於ThreadLocal物件的set()方法設定的值只對當前執行緒可見,那有什麼方法可以為ThreadLocal物件設定的值對所有執行緒都可見。
為此,我們可以通過ThreadLocal子類的實現,並覆寫initialValue()方法,就可以為ThreadLocal物件指定一個初始化值。如下所示:
private ThreadLocal myThreadLocal = new ThreadLocal<String>() { @Override protected String initialValue() { return "This is the initial value"; } };
此時,在set()方法呼叫前,當呼叫get()方法的時候,所有執行緒都可以看到同一個初始化值。
5、Full ThreadLocal Example
以下是一個完整的ThreadLocal示例:
public class ThreadLocalExample { public static class MyRunnable implements Runnable { private ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(); @Override public void run() { threadLocal.set( (int) (Math.random() * 100D) ); try { Thread.sleep(2000); } catch (InterruptedException e) { } System.out.println(threadLocal.get()); } } public static void main(String[] args) { MyRunnable sharedRunnableInstance = new MyRunnable(); Thread thread1 = new Thread(sharedRunnableInstance); Thread thread2 = new Thread(sharedRunnableInstance); thread1.start(); thread2.start(); thread1.join(); //wait for thread 1 to terminate thread2.join(); //wait for thread 2 to terminate } }
上面建立了兩個執行緒共享一個MyRunnable例項。每個執行緒執行run()方法的時候,會給同一個ThreadLocal例項設定不同的值。如果呼叫set()方法的時候用synchronized關鍵字同步,而且不是一個ThreadLocal物件例項,那麼第二個執行緒將會覆蓋第一個執行緒所設定的值。
然而,由於是ThreadLocal物件,所以兩個執行緒無法看到彼此的值。因此,可以設定或者獲取不同的值。
6、InheritableThreadLocal
InheritableThreadLocal類是ThreadLocal的子類。為了解決ThreadLocal例項內部每個執行緒都只能看到自己的私有值,所以InheritableThreadLocal允許一個執行緒建立的所有子執行緒訪問其父執行緒的值。