17

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

Which outputs

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 

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

Such so that my result is:

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 

instead of the first one?

2
  • 3
    I wouldn't expect so. But why is this ThreadLocal in the first place, instead of just created in your main method and then passed on explicitly to the lambda? Commented Nov 25, 2015 at 21:38
  • 5
    Are you trying to cross the streams? I've heard it would be bad. Commented Nov 25, 2015 at 21:39

1 Answer 1

15

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 case is.

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

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.

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

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Yes, my example wasn't giving too much information about the use case. The actual use case is together with some other code (apart of the parallel() consumer) and the ThreadLocal is being populated in a Servlet filter and then used in a Spring MVC controller, and some times cloned for various runnable implementations across the board (service calls, etc). So there will be various calls down the road which are ThreadContext.get(something). Thanks for explaining the InheritableThreadLocal, I will give it a try!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.