web-dev-qa-db-ja.com

スレッドまたはThreadPool?固定または動的ThreadPool?

Javaプログラムが入力をポートでリッスンします。入力に基づいて、Webサービスを呼び出し、クライアントプログラムに成功/失敗を返します。

クライアント接続ごとにスレッドをフォークします。プログラムに接続するクライアントへの応答は迅速でなければなりません。

これらは私が検討している選択肢です

  1. 通常のスレッドを使用する
  2. ExecutorServicenewFixedThreadPoolを併用
  3. ExecutorServicenewCachedThreadPoolを併用

私がプールを検討している理由は、私のスレッドが短命であるためです-スレッドはWebサービスを呼び出し、クライアントに結果を返し、接続を閉じます。

newFixedThreadPoolは正しい接続だとは思いません。接続がキューで待機してスレッドを取得するからです。

newCachedThreadPoolは、スレッドが1分後に死ぬことを除いて、完璧でした。私の場合、接続のバーストが発生します。つまり、複数の接続があり、その後数分間の停滞があり、その後再びバーストします。 CachedThreadPool内のスレッドは停止し、再作成する必要があると思います。この場合、場合によっては#1のように機能する可能性があります。

理想的には、最小でnewCachedThreadPoolを使用したいと思っていました。つまり、スレッド数が20を下回ることは決してないという設定です。したがって、アイドルスレッドは強制終了されますが、最小しきい値を下回ることはありません。

このようなものはありますか?または、より良い代替手段はありますか?

8
user93353

Executorsクラスのメソッドは、一般的な使用例の便利なメソッドです。スレッドプールを作成するために利用できるオプションはもっとたくさんあります。

Executors.newCachedThreadPool()と同じことを作成しますが、最低20スレッドを使用します(これは、コアスレッドサイズが0から20に変更された、Executorsのメソッドからコピーされます)。

        return new ThreadPoolExecutor(20, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
8
Michael Krussel

興味深い質問です。

newCachedThreadPoolに対してお勧めします。上限なしで、必要な数のスレッドを生成します。悪い!

マイケルによって提案されたアプローチは良いようです。 ThreadPoolExecutorを使用し、コアプールサイズとして適切な数値を使用します。スレッドの最大数を、許容したい(またはサーバーが処理できる)値に設定します。

リソースを使い果たすと、ほとんど何もできないことに注意してください(キューがいっぱいで、最大数のスレッドが機能しています)。その場合、2つのことの1つを実行できます。新しい接続をドロップするか、バックプレッシャーを適用します(ブロックして新しい作業を受け入れないでください)。デフォルトでは、TPEはフルになるとRejectedExecutionExceptionをスローしますが、ブロッキング動作を実装するのは簡単です。実際、これが BlockingThreadPoolExecutor のオープンソース実装です。

4
goblinjuice

RejectedExecutionExceptionについて:

BlockingThreadPoolExecutorの代わりに、 CallerRunPolicy ハンドラーを使用するようにThreadPoolExecutorにRejectedExecutionHandlerを設定するだけです。

2
silmarx

threadPoolExecutorのラッパーを使用するのが良い方法だと思います。初期化(プール名、スレッド数など)と、initメソッドの1つで以前に作成したプールにタスク(Runnable)を追加するメソッドを公開できるラッパー。

ラッパーは、他のコードに影響を与えずに、使用するプールを変更でき、さらにスレッド数、監査(タスクの前/後)などの他のメソッドを一貫した方法で公開できます。

また、プールに独自のスレッドファクトリを実装することもできます。これには、カスタム名、優先度、および少なくともUncaughtExceptionHandlerをフックして、エラーをログに記録することができます。

私のプールラッパーには次のようなメソッドがあります

public static boolean queqeAdd(String poolName, int coreSize, int maxSize, boolean usePriorityQ, String threadNamePrefix, int timeOutSeconds) {...}
public static void execute(String poolName, Runnable command, Integer priority){...}
public static long tasksCount(String poolName) 
public static long tasksCompletedCount(String poolName) 
public static int clearPoolRequest(String poolName, boolean intrpt) 
public static int shutdownPoolRequest(String poolName) 
public static void executeAll(String poolName, List<Runnable> lst) 
0
tgkprog