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
终端操作的任何池),则不会出现这种情况。