I am trying to use both InheritableThreadLocal
and a ThreadPoolExecutor
.
This breaks down because ThreadPoolExecutor
reuses threads for each pool (it is a pool, after all), meaning the InheritableThreadLocal
doesn't work as expected. Now the problem seems obvious to me, but it was particularly snarly to track down.
I use InheritableThreadLocal
so that each of several top-level processes has its own database connection for itself and any sub-processes it spawns. I don't just use one shared connection pool because each top-level process will do a lot of multi-step work with its connection before committing to the database and/or preparing a lot of PreparedStatements that are used over and over.
I use a shared ThreadPoolExecutor
between these top-level processes because there are certain behaviors that need to be gated. e.g. Even though I might have 4 top-level processes running, I can only have any one process writing to the database at a time (or the system needs to gate on some other shared resource). So I'll have the top-level process create a Runnable
and send it to the shared ThreadPoolExecutor
to make sure that no more than one (or two or three as the case may be) are running at the same time across the entire system.
The problem is that because the ThreadPoolExecutor
reuses its threads for the pools, the InheritableThreadLocal
is picking up the original value that was run in that pool rather than the value that was in the top-level process which sent the Runnable to the ThreadPoolExecutor
.
Is there any way to force the worker pool in the ThreadPoolExecutor
to use the InheritableThreadLocal
value that was in the context of the process which created the Runnable rather than in the context of the reused thread pool?
Alternatively, is there any implementation of ThreadPoolExecutor
that creates a new thread each time it starts a new Runnable? For my purposes I only care about gating the number of simultaneously running threads to a fixed size.
Is there any other solution or suggestion people have for me to accomplish what I've described above?
(While I realize I could solve the problem by passing around the database connection from class to class to subthread to subthread like some kind of community bicycle, I'd like to avoid this.)
There is a previous question on StackOverflow, InheritableThreadLocal and thread pools, that addresses this issue as well. However, the solution to that problem seems to be that it's a poor use case for InheritableThreadLocal, which I do not think applies to my situation.
Thanks for any ideas.
using InheritedThreadLocal
is almost surely wrong. Probably you'd have not asked the question if you can fit that bizarre tool.
First and foremost it's horribly leak-prone and often the value(s) escapes in some totally strange threads.
As for the Runnable being associate w/ a context.
Override publicvoid execute(Runnable command)
of the ExecutorPool
and wrap the Runnable
withing some context carrying the value you want in the first place from the InheritedThreadLocal
.
The wrapping class shall look something like
class WrappedRunnable extends Runnable{
static final ThreadLocal<Ctx> context=new ThreadLocal<Ctx>();
final Runnable target;
final Ctx context;
WrappedRunnable(Ctx context, Runnable target){...}
public void run(){
ctx.set(context);
try{
target.run();
}finally{
ctx.set(null);//or ctx.remove()
}
}
}
Alternatively, is there any implementation of ThreadPoolExecutor that creates a new >thread each time it starts a new Runnable? For my purposes I only care about gating the >number of simultaneously running threads to a fixed size.
While truly bad from performance point of view, you can implement your own, basically you need only execute(Runnable task)
method for the Executor
that spawns new thread and starts it.