nfs*_*ake 5 java concurrency scala thread-local
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
产量
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
Run Code Online (Sandbox Code Playgroud)
我期待输出的最后一行中的"NewInitialValue",因为333 Thread产生了Thread 444,而tl是一个可继承的本地线程.
是什么导致了这个问题,如何解决?
Sot*_*lis 10
InheritableThreadLocal当您无法控制线程的创建时,您不应该依赖它.javadoc说:
[...]创建子线程时,子进程接收父对象具有值的所有可继承线程局部变量的初始值.
在您的示例中,线程由ExecutorService返回的创建Executors.newFixedThreadPool(2)
这是一个执行器,它将使用最多两个线程来执行您的任务.来自javadoc
创建一个线程池,该线程池重用在共享的无界队列中运行的固定数量的线程.在任何时候,最多
nThreads线程都将是活动处理任务.如果在所有线程都处于活动状态时提交了其他任务,则它们将在队列中等待,直到线程可用.
这是一个实现细节,但这些线程是根据需要延迟创建的.当您提交第一个任务时111,调用submit将创建并启动一个新线程.这个新线程将继承该值InitialValue.类似地,当这个线程提交第二个任务时222,它的调用submit将强制创建第二个线程,该线程也将继承InitialValue.
然后你提交第三个任务,333覆盖InheritableThreadLocal它的值并打印出来.提交第四个任务时444,ExecutorService使用现有线程执行它.该线程已经有一个值,先前继承过.
怎么解决
如果不知道自己想做什么,这很难回答.但是,如果你想有效地使用InheritableThreadLocal它,那一切都归结为知道和控制线程的创建,因此也就是继承链.
例如,您可以创建并使用ExecutorService为每个提交的任务创建和使用新线程的线程.
类似地,您可以使用另一种机制来传播该值:一个AtomicReference或不可变值的lambda捕获.
| 归档时间: |
|
| 查看次数: |
4333 次 |
| 最近记录: |