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)
}
}
}
Output
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
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 ?
You shouldn't rely on
InheritableThreadLocal
when you don't have control over the creation of threads. The javadoc states:In your example, threads are being created by the
ExecutorService
returned byExecutors.newFixedThreadPool(2)
That's an executor that will use up to two threads to execute your tasks. From the javadoc
This is an implementation detail, but those threads are created lazily, as needed. When you submit the first task,
111
, the call tosubmit
will create and start a new thread. This new thread will inherit the valueInitialValue
. Similarly, when this thread submits the second task,222
, its call tosubmit
will force the creation of the second thread which will also inherit theInitialValue
.Then you submit the third task,
333
, overwrite theInheritableThreadLocal
's value and print it. When you submit the fourth task444
, theExecutorService
uses existing threads to execute it. That thread already has a value, inherited earlier.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.You could create and use an
ExecutorService
that creates and uses a new thread for each submitted task, for example.Similarly, you could use another mechanism to propagate that value: an
AtomicReference
or lambda capture of an immutable value.