InheritableThreadLocal 和线程池
我有一个问题,我真的认为没有解决方案,但无论如何我都会在这里尝试。我的应用程序使用线程池,并且该池中的一些线程具有可继承的线程局部变量。我扩展了 ThreadPoolExecutor 类,以便在线程执行完毕时基本上清除线程局部变量(在 afterExecute 回调方法中)。
据我了解,当您有 InheritableThreadLocal 变量时,在初始化线程时会调用 childValue() 方法,以从父线程获取 ThreadLocal 变量的值。然而,在我的例子中,下次使用线程时(使用一次后),InheritableThreadLocal 变量的值为 null(因为它之前已在 afterExecute 中清除)。有没有办法在 beforeExecute 中访问父线程的线程局部变量,以便我基本上可以模拟 InheritableThreadLocal 中的 childValue 方法在线程创建时所做的操作。
I have a problem which I don't really think has a solution but I'll try here anyway. My application uses a thread pool and some of the threads in this pool have an inheritable thread local variable. I've extended the ThreadPoolExecutor class to essentially clear out the thread local variable (in the afterExecute call back method) when a thread is done executing.
I understand that when you have an InheritableThreadLocal variable, the childValue() method is called when the thread is initialized to get the ThreadLocal variable's value from the parent thread. However, in my case the next time the thread is used (after being used once), the value of the InheritableThreadLocal variable is null (because it was previously cleared out in afterExecute). Is there a way to access the parent thread's thread local variable in beforeExecute so that I can essentially simulate what the childValue method in InheritableThreadLocal does at the time of thread creation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
听起来这对于线程局部变量的“可继承”风格来说是一个糟糕的用例。
我的建议是只使用常规的
TheadLocal
并显式地进行初始化;例如将初始值作为参数或其他内容从父线程传递给子线程。(我建议您通过让子线程在启动时立即获取值来强制子线程初始化。但这存在竞争条件的风险;例如,如果父线程在子线程之前返回到池中线程开始执行。)
没有办法做到这一点。
而且,从您的其他评论来看,我怀疑您的意思是正常意义上的“父”和“子”……父线程创建子线程。
但这里有一个想法。不要尝试在线程之间共享变量,而是共享一个固定值(例如请求 ID),并将其用作共享
Map
的键。使用Map
条目作为共享变量。It sounds like this is a poor use-case for the "inheritable" flavour of thread-locals.
My advice would be to just use a regular
TheadLocal
and do the initialization explicitly; e.g. passing the initial value from the parent thread to the child thread as a parameter or something.(I was going suggest that you force initialization of the thread-local the child thread by having it fetch the value as soon as it starts. But that risks a race-condition; e.g. if the parent thread is returned to the pool before the child thread starts executing.)
There isn't a way to do this.
And, judging from your other comments, I doubt that you mean "parent" and "child" in the normal sense ... where the parent thread creates the child thread.
But here's an idea. Instead of trying to share a variable between threads, share a fixed value (e.g. a request ID), and use that as a key for a shared
Map
. Use theMap
entries as the shared variables.runnable 的构造函数在调用者的线程中运行,而 run 方法在子线程中运行。您可以使用此事实将信息从父线程传输到子线程。看:
这就是结果
The constructor of a runnable runs in the thread of the caller, whereas the run method runs in the child thread. You can use this fact to transfer information from the parent to the child thread. See:
And this is the result
我遇到了类似的问题,最终创建了一个
ForkListeningExecutorService
,它包装了一个ExecutorService
(请参阅此处)。每当任务提交给执行器或任务结束时,包装器都会向侦听器发送事件。然后,您可以使用侦听器在线程之间传递您想要的任何内容。侦听器如下所示:因此,您可以简单地包装它(或任何其他
ExecutorService
实现)并在侦听器中传递状态,而不是扩展 ThreadPoolExecutor ,如下所示:输出看起来像这样:
I had a similar problem and ended up creating a
ForkListeningExecutorService
which wraps anExecutorService
(see here). The wrapper sends events to a listener whenever a task is submitted to the executor or when it ends. You can then use the listener to pass whatever you want across the threads. This is how the Listener looks like:So, instead of extending
ThreadPoolExecutor
, you can simply wrap it (or whatever otherExecutorService
implementation) and pass the state within the listener like this:The output looks then like this: