我试图弄清楚如何在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
有没有办法将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
而不是第一个?
正如Louis在评论中所述,您的示例可以简化为捕获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
InheritableThreadLocal
此类扩展ThreadLocal为提供 从父线程到子线程的值继承 :创建 子线程 时,子级将接收父级具有值的所有可继承线程局部变量的初始值。
ThreadLocal
在你的情况下,宣布val作为InheritableThreadLocal,因为Thread实例为创建parallel()中ForkJoinPool#commonPool()懒洋洋地创建,他们会从值的所有继承set的main方法(和线程)。
val
Thread
parallel()
ForkJoinPool#commonPool()
set
main
如果您在原始线程中设置值之前以某种方式使用了commonPool(或parallel调用了终端操作的任何池),情况就不会如此InhertiableThreadLocal。
commonPool
parallel
InhertiableThreadLocal