InheritableThreadLocal を ThreadPoolExecutor で使用する -- または -- スレッドを再利用しない ThreadPoolExecutor 質問する

InheritableThreadLocal を ThreadPoolExecutor で使用する -- または -- スレッドを再利用しない ThreadPoolExecutor 質問する

InheritableThreadLocalと の両方を使用しようとしていますThreadPoolExecutor

これは、各プールのスレッドを再利用するためThreadPoolExecutor(結局のところ、プールです)、InheritableThreadLocal期待どおりに動作しないことを意味します。問題は私には明らかですが、追跡するのは特に困難でした。

私は、InheritableThreadLocal複数のトップレベル プロセスのそれぞれが、それ自体とそれが生成するサブプロセスに対して独自のデータベース接続を持つように使用します。各トップレベル プロセスは、データベースにコミットしたり、何度も使用される多数の PreparedStatements を準備したりする前に、その接続を使用して多数のマルチステップ作業を実行するため、共有接続プールを 1 つだけ使用しません。

これらのトップレベル プロセス間で共有を使用するのThreadPoolExecutorは、ゲート制御が必要な特定の動作があるためです。たとえば、トップレベル プロセスが 4 つ実行されている場合でも、データベースに書き込むことができるプロセスは一度に 1 つだけです (または、システムが他の共有リソースをゲート制御する必要があります)。そのため、トップレベル プロセスで を作成しRunnable、それを共有に送信して、ThreadPoolExecutorシステム全体で同時に 1 つ (または、場合によっては 2 つまたは 3 つ) しか実行されないようにします。

問題は、 がThreadPoolExecutorプールのスレッドを再利用するため、 が、InheritableThreadLocalRunnable を に送信したトップレベル プロセスの値ではなく、そのプールで実行された元の値を取得することですThreadPoolExecutor

  • 再利用されたスレッド プールのコンテキストではなく、Runnable を作成したプロセスのコンテキストにあった値をワーカー プールで強制ThreadPoolExecutor的に使用させる方法はありますか?InheritableThreadLocal

  • あるいは、新しい Runnable を開始するたびに新しいスレッドを作成する実装はありますかThreadPoolExecutor? 私の目的としては、同時に実行されるスレッドの数を固定サイズに制限することだけを考えています。

  • 上記で説明したことを実現するための他の解決策や提案はありますか?

(ある種のコミュニティ自転車のように、データベース接続をクラスからクラスへ、サブスレッドからサブスレッドへと渡すことで問題を解決できることはわかっていますが、これは避けたいと思います。)

StackOverflowに以前の質問があります。InheritableThreadLocal とスレッドプール、これもこの問題に対処しています。ただし、その問題の解決策は、InheritableThreadLocal の不適切な使用例であるということのようですが、私の状況には当てはまらないと思います。

何かアイデアがあれば教えてください。

ベストアンサー1

使用はInheritedThreadLocalほぼ間違いなく間違いです。その奇妙なツールに適合できるかどうかは、おそらく質問しなかったでしょう。まず第一に、それはひどくリークしやすく、値がまったく奇妙なスレッドで逃げてしまうことがよくあります。

Runnable がコンテキストに関連付けられている場合、void execute(Runnable command)のpublic をオーバーライドしExecutorPoolRunnableから最初に必要な値を保持するコンテキスト内で をラップしますInheritedThreadLocal

ラッピングクラスは次のようになります

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()
    }
  }
}

あるいは、新しい Runnable を開始するたびに新しいスレッドを作成する ThreadPoolExecutor の実装はありますか? 私の目的としては、同時に実行されるスレッドの数を固定サイズに制限することだけを考えています。

パフォーマンスの観点から見ると本当に悪いですが、独自に実装することができます。基本的には、新しいスレッドを生成して開始するexecute(Runnable task)メソッドのみが必要です。Executor

おすすめ記事