JavaのThreadLocalの例を示します。
JavaのThreadLocalは、スレッド固有の変数を作成するために使用されます。オブジェクトのすべてのスレッドがその変数を共有するため、変数はスレッドセーフではありません。スレッドセーフを実現するには同期化を使用できますが、同期化を避けたい場合はThreadLocal変数を使用することができます。
JavaのThreadLocal
すべてのスレッドには、それぞれ独自のThreadLocal変数があり、get()メソッドやset()メソッドを使用してデフォルト値を取得したり、スレッド内で値を変更することができます。通常、ThreadLocalインスタンスは、スレッドに関連付けたい状態を持つクラスのプライベートな静的フィールドとして定義されます。
JavaのThreadLocalの例
(The wording may vary slightly depending on the context, but this conveys the same meaning.)
JavaプログラムにおけるThreadLocalの使用例を示し、各スレッドが独自のThreadLocal変数のコピーを持っていることを証明する小さな例をここに示します。ThreadLocalExample.java
package com.scdev.threads;
import java.text.SimpleDateFormat;
import java.util.Random;
public class ThreadLocalExample implements Runnable{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
public static void main(String[] args) throws InterruptedException {
ThreadLocalExample obj = new ThreadLocalExample();
for(int i=0 ; i<10; i++){
Thread t = new Thread(obj, ""+i);
Thread.sleep(new Random().nextInt(1000));
t.start();
}
}
@Override
public void run() {
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
//formatter pattern is changed here by thread, but it won't reflect to other threads
formatter.set(new SimpleDateFormat());
System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
}
}
上記のJava ThreadLocalの例プログラムの出力は、次のとおりです。
Thread Name= 0 default Formatter = yyyyMMdd HHmm
Thread Name= 1 default Formatter = yyyyMMdd HHmm
Thread Name= 0 formatter = M/d/yy h:mm a
Thread Name= 2 default Formatter = yyyyMMdd HHmm
Thread Name= 1 formatter = M/d/yy h:mm a
Thread Name= 3 default Formatter = yyyyMMdd HHmm
Thread Name= 4 default Formatter = yyyyMMdd HHmm
Thread Name= 4 formatter = M/d/yy h:mm a
Thread Name= 5 default Formatter = yyyyMMdd HHmm
Thread Name= 2 formatter = M/d/yy h:mm a
Thread Name= 3 formatter = M/d/yy h:mm a
Thread Name= 6 default Formatter = yyyyMMdd HHmm
Thread Name= 5 formatter = M/d/yy h:mm a
Thread Name= 6 formatter = M/d/yy h:mm a
Thread Name= 7 default Formatter = yyyyMMdd HHmm
Thread Name= 8 default Formatter = yyyyMMdd HHmm
Thread Name= 8 formatter = M/d/yy h:mm a
Thread Name= 7 formatter = M/d/yy h:mm a
Thread Name= 9 default Formatter = yyyyMMdd HHmm
Thread Name= 9 formatter = M/d/yy h:mm a
以下は、出力からわかるように、スレッド0はフォーマッタの値を変更しましたが、スレッド2のデフォルトのフォーマッタは初期値と同じままです。他のスレッドについても同じパターンが見られます。更新:Java 8では、ThreadLocalクラスが新しいメソッドwithInitial()で拡張され、Supplier関数インターフェースを引数にとるようになりました。したがって、ラムダ式を使用して簡単にThreadLocalインスタンスを作成することができます。例えば、上記のフォーマッタThreadLocal変数は以下のように1行で定義することができます。
private static final ThreadLocal<SimpleDateFormat> formatter =
ThreadLocal.<SimpleDateFormat>withInitial
(() -> {return new SimpleDateFormat("yyyyMMdd HHmm");});
Java 8の機能に初めて触れる方は、「Java 8の機能」と「Java 8の関数型インターフェース」をチェックしてください。これでjavaプログラミングにおけるThreadLocalについては終わりです。参考資料:APIドキュメント