Java 8并行流和ThreadLocal



我正试图弄清楚如何在Java 8并行流中复制ThreadLocal值。

因此,如果我们考虑这个:

    public class ThreadLocalTest {
        public static void main(String[] args)  {
            ThreadContext.set("MAIN");
            System.out.printf("Main Thread: %sn", ThreadContext.get());
            IntStream.range(0,8).boxed().parallel().forEach(n -> {
                System.out.printf("Parallel Consumer - %d: %sn", 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 from 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: %sn", value);
    IntStream.range(0,8).boxed().parallel().forEach(n -> {
        System.out.printf("Parallel Consumer - %d: %sn", n, value);
    });
}

从你的例子来看,完整的用例是什么并不明显

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

此类扩展ThreadLocal以提供对父线程到子线程:创建子线程时child接收所有本地可继承线程的初始值父级具有值的变量。

在将val声明为InheritableThreadLocal的情况下,由于在ForkJoinPool#commonPool()中为parallel()创建的Thread实例是延迟创建的,因此它们都将继承自main方法(和线程)中的值set

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

相关内容

  • 没有找到相关文章

最新更新