1. 程式人生 > >《Java併發性和多執行緒介紹》-Java TheadLocal

《Java併發性和多執行緒介紹》-Java TheadLocal

原文連結 作者:Jakob Jenkov   檢視全部文章

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允許一個執行緒建立的所有子執行緒訪問其父執行緒的值。


oshare目前就職於淘汽檔口,喜歡新技術,希望自建一套個人學習體系。樂於分享,喜歡參與開源專案。開始研究Docker相關的技術,有興趣的TX可以一起交流。