ExecutorService线程不继承InheritableThreadLocal值 [英] InheritableThreadLocal value not inherited by ExecutorService threads

查看:177
本文介绍了ExecutorService线程不继承InheritableThreadLocal值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

import java.util.concurrent.Executors
import scala.concurrent.{ExecutionContext, Future}

object TestInheritableThreadLocal {

  def main(args: Array[String]): Unit = {

    implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(2))

    val tl: InheritableThreadLocal[String] = new InheritableThreadLocal[String]()
    tl.set("InitialValue")

    Future {
      println("111 " + Thread.currentThread() + tl.get())
      Future {
        println("222 " + Thread.currentThread() + tl.get())
      }
    }
    Thread.sleep(3000)

    Future {
      tl.set("NewInitialValue")
      println("333 " + Thread.currentThread() + tl.get())
      Future {
        println("444 " + Thread.currentThread() + tl.get())
      }
      Thread.sleep(3000)
    }
  }
}

输出

111 Thread[pool-1-thread-1,5,main]InitialValue
222 Thread[pool-1-thread-2,5,main]InitialValue
333 Thread[pool-1-thread-1,5,main]NewInitialValue
444 Thread[pool-1-thread-2,5,main]InitialValue

我期待输出的最后一行中出现NewInitialValue,因为333 Thread生成了Thread 444,而tl是一个可继承的本地线程。

I was expecting "NewInitialValue" in the last line of output since 333 Thread spawned of Thread 444 and tl is a Inheritable thread local.

导致此问题的原因是什么以及如何解决?

What is causing this issue and how can it be resolved ?

推荐答案

你不应该依赖 InheritableThreadLocal 。 javadoc声明:

You shouldn't rely on InheritableThreadLocal when you don't have control over the creation of threads. The javadoc states:


[...]创建子线程时,子接收
的初始值全部可继承父元素具有
值的线程局部变量。

[...] when a child thread is created, the child receives initial values for all inheritable thread-local variables for which the parent has values.

在您的示例中,线程由<$创建c $ c> ExecutorService 由 Executors.newFixedThreadPool(2)

In your example, threads are being created by the ExecutorService returned by Executors.newFixedThreadPool(2)

这是执行者将使用最多两个线程来执行您的任务。来自javadoc

That's an executor that will use up to two threads to execute your tasks. From the javadoc


创建一个线程池,该线程池重用在共享无界队列中运行
的固定数量的线程。在任何时候,最多 nThreads 线程
将是活动处理任务。如果在所有线程都处于活动状态时提交额外的任务
,它们将在队列中等待,直到
线程可用。

Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue. At any point, at most nThreads threads will be active processing tasks. If additional tasks are submitted when all threads are active, they will wait in the queue until a thread is available.

这是一个实现细节,但这些线程是根据需要延迟创建的。当您提交第一个任务 111 时,对 submit 的调用将创建并启动一个新线程。这个新线程将继承值 InitialValue 。类似地,当此线程提交第二个任务 222 时,其对 submit 的调用将强制创建第二个线程它还将继承 InitialValue

This is an implementation detail, but those threads are created lazily, as needed. When you submit the first task, 111, the call to submit will create and start a new thread. This new thread will inherit the value InitialValue. Similarly, when this thread submits the second task, 222, its call to submit will force the creation of the second thread which will also inherit the InitialValue.

然后你提交第三个任务, 333 ,覆盖 InheritableThreadLocal 的值并打印出来。当您提交第四个任务 444 时, ExecutorService 使用现有线程来执行它。该线程已经有一个值,在之前继承。

Then you submit the third task, 333, overwrite the InheritableThreadLocal's value and print it. When you submit the fourth task 444, the ExecutorService uses existing threads to execute it. That thread already has a value, inherited earlier.


如何解决

how can it be resolved

如果不知道自己想做什么,这很难回答。但是,如果你想有效地使用 InheritableThreadLocal ,那么这一切都归结为知道和控制线程的创建,因此也就是继承链。

That's hard to answer without knowing what you want to do. But, if you want to effectively use InheritableThreadLocal, it all comes down to knowing and controlling the creation of threads, and therefore the inheritance chain.

您可以创建并使用 ExecutorService ,例如,为每个提交的任务创建并使用新线程。

You could create and use an ExecutorService that creates and uses a new thread for each submitted task, for example.

同样,您可以使用另一种机制来传播该值: AtomicReference 或不可变值的lambda捕获。

Similarly, you could use another mechanism to propagate that value: an AtomicReference or lambda capture of an immutable value.

这篇关于ExecutorService线程不继承InheritableThreadLocal值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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