2015-11-25 17 views
8

Java 8の並列ストリームでThreadLocal値をコピーするにはどうすればいいですか?Java 8の並列ストリームとThreadLocal

我々は考えるのであれば、この:

public class ThreadLocalTest { 

     public static void main(String[] args) { 
      ThreadContext.set("MAIN"); 
      System.out.printf("Main Thread: %s\n", ThreadContext.get()); 

      IntStream.range(0,8).boxed().parallel().forEach(n -> { 
       System.out.printf("Parallel Consumer - %d: %s\n", n, ThreadContext.get()); 
      }); 
     } 

     private static class ThreadContext { 
      private static ThreadLocal<String> val = ThreadLocal.withInitial(() -> "empty"); 

      public ThreadContext() { 
      } 

      public static String get() { 
       return val.get(); 
      } 

      public static void set(String x) { 
       ThreadContext.val.set(x); 
      } 
     } 
    } 

Main Thread: MAIN 
Parallel Consumer - 5: MAIN 
Parallel Consumer - 4: MAIN 
Parallel Consumer - 7: empty 
Parallel Consumer - 3: empty 
Parallel Consumer - 1: empty 
Parallel Consumer - 6: empty 
Parallel Consumer - 2: empty 
Parallel Consumer - 0: MAIN 

を出力するには、私は、各並列のために生み出されているスレッドにmain()メソッドからのThreadLocalのクローンを作成するための方法はあります実行?

ようなので、私の結果であること:代わりに、最初の1の

Main Thread: MAIN 
Parallel Consumer - 5: MAIN 
Parallel Consumer - 4: MAIN 
Parallel Consumer - 7: MAIN 
Parallel Consumer - 3: MAIN 
Parallel Consumer - 1: MAIN 
Parallel Consumer - 6: MAIN 
Parallel Consumer - 2: MAIN 
Parallel Consumer - 0: MAIN 

+3

私はそうは思わないでしょう。しかし、この 'ThreadLocal'はなぜあなたのメインメソッドで作成されたのではなく、明示的にラムダに渡されたのでしょうか? –

+4

ストリームを通過しようとしていますか?私はそれが悪いと聞いた。 – zapl

答えて

7

As Louis has stated in the comments、あなたの例は非常によくこれは、完全なユースケースが何であるかをあなたの例から明らかではありませんラムダ式

public static void main(String[] args) { 
    String value = "MAIN"; 
    System.out.printf("Main Thread: %s\n", value); 

    IntStream.range(0,8).boxed().parallel().forEach(n -> { 
     System.out.printf("Parallel Consumer - %d: %s\n", n, value); 
    }); 
} 

内のローカル変数の値を取得するまで低減することができます。

あなたはスレッドががあなたのメインスレッドからを開始します正確に何を知っている場合、あなたはこのクラスは、子スレッドに 親スレッドから値の継承を提供するために、ThreadLocalを拡張しInheritableThreadLocal

を使用して検討すること子スレッドが作成されると、 子は、親が値を持つすべての継承可能なスレッドローカル 変数の初期値を受け取ります。あなたのケースでは

ForkJoinPool#commonPool()parallel()のために作成さThreadインスタンスはあとで生成されているので、InheritableThreadLocalとしてvalを宣言し、それらはすべてmain方法(およびスレッド)の値setから継承します。

あなたは何とかcommonPool(または任意のプールparallel端末操作は上と呼ばれた)を使用した場合、あなたは元のスレッドでInhertiableThreadLocal値を設定する前に、これがケースではありません。

+0

はい、私の例では、ユースケースに関する情報をあまりにも多く与えていませんでした。実際のユースケースは、他のコード(parallel()コンシューマを除く)と一緒にあり、ThreadLocalはサーブレットフィルタに入れられ、Spring MVCコントローラで使用され、ボード上のさまざまな実行可能な実装のためにサービスコールなど)。したがって、道にはThreadContext.get(何か)という様々な呼び出しがあります。 InheritableThreadLocalを説明してくれてありがとう、私はそれを試してみましょう! –

関連する問題