20

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.

Benjamin W.
  • 46,058
  • 19
  • 106
  • 116
Jeff Goldberg
  • 931
  • 1
  • 9
  • 20

4 Answers4

7

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.

bestsss
  • 11,796
  • 3
  • 53
  • 63
  • 1
    What makes you say that InheritableThreadLocal is leak prone? I'm Googling about it and not seeing any articles or examples of where it causes memory leaks. Can you point me to some sources? – Jeff Goldberg Jan 26 '12 at 03:28
  • @JeffGoldberg, well, I know very well how it's implemented and I do a lot of infrastructure/middleware. ThreadLocal is leak prone and inherited version is very leak prone. Virtually you cant control when a new thread is spawned for whatever reason (JDK itself does that). A long running thread would leak the value and its classloader and there's no way to stop that far-far away thread from holding the reference to otherwise useless object. `childValue` can mend the case but it's called in a thread that holds it, and the new target thread is unknown... – bestsss Jan 26 '12 at 10:06
  • A quick note: This approach did work. I ended up taking the advice from @forty-two and changing the approach instead, otherwise I would have selected this as the answer. Thanks for the advice and help. – Jeff Goldberg Jan 30 '12 at 22:16
5

Instead of using a ThreadPoolExecutor to protect shared resources, why not use a java.util.concurrent.Semaphore? The sub tasks you create would run to completion in their own threads, but only after having acquired a permit from the semaphore, and of course releasing the permit when done.

forty-two
  • 12,204
  • 2
  • 26
  • 36
  • I haven't used Semaphores so I will look into this. We use a lot of the other features of Executors (Futures, timeouts, etc.) but it's possible I can do that with Semaphores or that I can use a regular executor (not thread pool) along with semaphores to get everything I need. Thanks. – Jeff Goldberg Jan 27 '12 at 18:28
  • This was the right way to go. Using Semaphores and FutureTasks was a more representative paradigm for what we wanted to do. After the change the code was greatly simplified, which is always a good sign. Plus it solved any InheritableThreadLocal issues. – Jeff Goldberg Jan 30 '12 at 17:16
0

We had the same issue earlier and we solved this issue by writing ThreadLocalContextMigrator which basically copies the thread local context to the task that will be executed using a thread from the pool. The Task, while executing will collect more context info and upon completion of the task we copy it back.

Aravind Yarram
  • 78,777
  • 46
  • 231
  • 327
0

Why not just pass the current connection on to any sub-tasks spawned by the main task? maybe some sort of shared Context object?

jtahlborn
  • 52,909
  • 5
  • 76
  • 118