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


8

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

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

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

  1. 通常のスレッドを使用する
  2. と使用ExecutorServiceするnewFixedThreadPool
  3. と使用ExecutorServiceするnewCachedThreadPool

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

newFixedThreadPool接続がキューでスレッドを取得するために待機しているため、私は正しいことだとは思いません。

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

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

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


独自のソケットサーバーの代わりにQuickServer.orgを見てください。それはあなたが望むことを行います->ソケットとスレッド、そして多くのサンプルがあります。30分で実行できます。テスト済みで安定しており、3つのプロジェクトで使用しています。「堅牢なマルチクライアントTCPサーバーアプリケーションをすばやく作成するためのオープンソースJavaライブラリ/フレームワーク」
tgkprog 2013年

回答:


8

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

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

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

4

興味深い質問です。

私は反対することをお勧めしnewCachedThreadPoolます。上限なしで、必要な数のスレッドを生成します。悪い!

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

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


2

RejectedExecutionExceptionについて:

BlockingThreadPoolExecutorの代わりに、ThreadPoolExecutorにRejectedExecutionHandlerを設定して、CallerRunPolicyハンドラーを使用できます。


0

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) 
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.