Java 8并行流和ThreadLocal [英] Java 8 parallel stream and ThreadLocal

查看:683
本文介绍了Java 8并行流和ThreadLocal的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图找出如何在Java 8并行流中复制ThreadLocal值。

I am trying to figure out how can I copy a ThreadLocal value in Java 8 parallel stream.

所以如果我们考虑这个:

So if we consider this:

    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()方法克隆到为每个并行执行生成的线程?

Is there a way for me to clone the ThreadLocal from main() method into the threads which are spawned for each parallel execution ?

这样我的结果是:

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表达式中捕获局部变量的值

As Louis has stated in the comments, your example can very well be reduced to capturing the value of a local variable in the lambda expression

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

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

It's not obvious from your example what the full use cases is.

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

If you know exactly what threads will be started from your main thread, you may consider using an InheritableThreadLocal


此类扩展 ThreadLocal 以提供
父值的继承线程到子线程
:当创建子线程时,
子节点接收父节点具有值的所有可继承线程局部
变量的初始值。

This class extends ThreadLocal to provide inheritance of values from parent thread to child thread: when a child thread is created, the child receives initial values for all inheritable thread-local variables for which the parent has values.

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

In your case, declaring val as an InheritableThreadLocal, since the Thread instances created for parallel() within the ForkJoinPool#commonPool() are created lazily, they would all inherit from the value set in the main method (and thread).

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

This wouldn't be the case if you somehow used the commonPool (or whatever pool the parallel terminal operation was called on) before you set the InhertiableThreadLocal value in the origin thread.

这篇关于Java 8并行流和ThreadLocal的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆