在ThreadPoolExecutor中使用InheritableThreadLocal – 或者 – 不重用线程的ThreadPoolExecutor

我试图使用InheritableThreadLocalThreadPoolExecutor

这会分解,因为ThreadPoolExecutor为每个池重用线程(毕竟它是一个池),这意味着InheritableThreadLocal不能按预期工作。 现在这个问题对我来说显而易见,但追踪却特别狡猾。

我使用InheritableThreadLocal以便几个顶级进程中的每一个都有自己的数据库连接以及它产生的任何子进程。 我不只是使用一个共享连接池,因为每个顶级进程在提交到数据库和/或准备大量反复使用的PreparedStatements之前,将使用其连接进行大量的多步骤工作。

我在这些顶级进程之间使用共享的ThreadPoolExecutor ,因为某些行为需要被门控。 虽然我可能有4个顶级进程在运行,但我一次只能有一个进程写入数据库(或者系统需要访问其他一些共享资源)。 因此,我将让顶级进程创建一个Runnable并将其发送到共享的ThreadPoolExecutor ,以确保在整个系统中同时运行不超过一个(或两个或三个)。

问题是因为ThreadPoolExecutor重用其池的线程,所以InheritableThreadLocal将获取在该池中运行的原始值,而不是将Runnable发送到ThreadPoolExecutor的顶级进程中的值。

  • 有没有办法强制ThreadPoolExecutor的工作池使用创建Runnable而不是在重用线程池的上下文中的进程上下文中的InheritableThreadLocal值?

  • 或者,是否有任何ThreadPoolExecutor实现,每次启动一个新的Runnable时都会创建一个新线程? 出于我的目的,我只关心将同时运行的线程的数量设置为固定大小。

  • 有没有其他解决方案或建议人们让我完成我上面描述的内容?

(虽然我意识到我可以通过将类数据库连接从类传递到子线程到子线程来解决问题,就像某种社区自行车一样,我想避免这种情况。)

还有一个关于StackOverflow, InheritableThreadLocal和线程池的问题也解决了这个问题。 但是,该问题的解决方案似乎是它对于InheritableThreadLocal来说是一个糟糕的用例,我不认为这适用于我的情况。

谢谢你的任何想法。

而不是使用ThreadPoolExecutor来保护共享资源,为什么不使用java.util.concurrent.Semaphore ? 您创建的子任务将在自己的线程中运行完成,但只有在从信号量获取许可后才能完成,当然在完成后释放许可。

使用InheritedThreadLocal几乎肯定是错误的。 可能你没有问过这个问题是否适合这个奇怪的工具。 首先,它可能非常容易泄漏,并且通常在一些完全奇怪的线程中逃脱价值。

对于具有上下文的Runnable是关联的。 覆盖ExecutorPool public void execute(Runnable command) ,并使用一些上下文包装Runnable ,该上下文从InheritedThreadLocal首先包含您想要的值。

包装类看起来像

 class WrappedRunnable extends Runnable{ static final ThreadLocal context=new ThreadLocal(); 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() } } } 

或者,是否有任何ThreadPoolExecutor的实现,每次启动一个新的Runnable时都会创建一个新的>线程? 出于我的目的,我只关心将同时运行的线程数>门控到固定大小。

虽然从性能的角度来看确实很糟糕,但是你可以实现自己的,基本上你只需要为生成新线程并启动它的Executor execute(Runnable task)方法。

我们之前遇到过相同的问题,我们通过编写ThreadLocalContextMigrator解决了这个问题,它基本上将线程本地上下文复制到将使用池中的线程执行的任务。 任务在执行时将收集更多上下文信息,完成任务后我们将其复制回来。

为什么不将当前连接传递给主任务生成的任何子任务? 也许是某种共享的Context对象?