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 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 

有没有办法让我将ThreadLocal从main()方法克隆到为每个并行执行生成的线程中?

这样我的结果是:

 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 

而不是第一个?

正如路易斯在评论中所说的那样 ,你的例子很可能被简化为捕获lambda表达式中局部变量的值

 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); }); } 

从您的示例中可以看出完整用例是什么。

如果您确切知道将从主线程启动哪些线程,则可以考虑使用InheritableThreadLocal

此类扩展ThreadLocal以提供从父线程到子线程的值的inheritance :当创建子线程时,子进程接收父对象具有值的所有可inheritance线程局部变量的初始值。

在您的情况下,将val声明为InheritableThreadLocal ,因为在ForkJoinPool#commonPool()中为parallel()创建的Thread实例是懒惰创建的,它们都将inheritance自main方法(和线程)中set的值。

如果您在原始线程中设置InhertiableThreadLocal值之前以某种方式使用了commonPool (或调用parallel终端操作的任何池),则不会出现这种情况。