12

ThreadPoolExecutor に送信されたタスクが長時間実行されるシナリオがあります。スレッド プールが開始されると、コア プール サイズ = 5、最大プール サイズ = 20、キュー サイズ 10 で開始します。このアプリケーションでは、約 10 個のタスクが送信されます。ほとんどの場合、これらのタスクは数分または数時間実行されてから完了します。ただし、5 つのタスクすべてが I/O で停止する状況がありました。その結果、コア プール サイズが最大に達しましたが、Threadpoolexecutor キューはいっぱいではありませんでした。そのため、追加の 5 つのタスクを実行する機会がありませんでした。そのようなシナリオをどのように処理できるかを提案してください。このような状況では、キューを小さくする方が良いオプションですか? threadPool を初期化する際の最適なキュー サイズは?

また、ハングしたタスクに関して、スレッドプールからスレッドを引き出す方法はありますか? その場合、少なくとも他のタスクが実行される可能性があります。

4

6 に答える 6

13

全体的な状況は次のようになります。

core pool size = 5,
max pool size = 20 and 
queue size of 10

10 件のタスクが送信されます。そのうち

  1. 5 タスクが I/O でハング => コア プール サイズのすべてのスレッドが占有されています。したがって、アイドルスレッドはありません。
  2. 5 タスクが残っています。アイドル状態のスレッドがなく、キューが 10 個のタスクに対応できるため、これらの 5 つのスレッドはキューに入れられます。これらのエンキューされたタスクは、キューがいっぱいになるか、コア プール内のいずれかのスレッドが解放されるまで実行されません。

したがって、あなたのプログラムはハングします。

ThreadPoolExecutor時計のダイナミクスの詳細については、こちらをご覧ください。このドキュメントの注目すべき点は次のとおりです。

  • 実行中のスレッドが corePoolSize よりも少ない場合、Executor は常に、キューに入れるよりも新しいスレッドを追加することを優先します。
  • corePoolSize 以上のスレッドが実行されている場合、Executor は常に、新しいスレッドを追加するよりも要求をキューに入れることを優先します。
  • 要求をキューに入れることができない場合、これが maximumPoolSize を超えない限り、新しいスレッドが作成されます。この場合、タスクは拒否されます。

EDIT
コアプールサイズを増やしたい場合は、setCorePoolSize(int corePoolSize)を使用できます。を増やすcorepoolsizeと、必要に応じて新しいスレッドが開始され、キューに入れられたタスクが実行されます。

于 2013-02-22T20:18:07.950 に答える
9

ThreadPoolExecutorのJavadocには、次のように記載されています。

任意のBlockingQueueを使用して、送信されたタスクを転送および保持できます。このキューの使用は、プールのサイズ設定と相互作用します。

  • 実行されているスレッドがcorePoolSize未満の場合、Executorは常に、キューイングではなく新しいスレッドを追加することを優先します。
  • corePoolSize以上のスレッドが実行されている場合、Executorは常に、新しいスレッドを追加するのではなく、リクエストをキューに入れることを優先します。
  • リクエストをキューに入れることができない場合、maximumPoolSizeを超えない限り、新しいスレッドが作成されます。超えた場合、タスクは拒否されます。

5つのスレッドが「ハング」した後でキューサイズを超えない限り、それ以上のスレッドを取得することはありません。

本当の答えは、スレッドがハングする原因となっている問題を修正することです。それ以外の場合は、スレッドの実行時間が長すぎる場合に、Futureによって返されたを使用してスレッドをキャンセルするスキームを実装する必要があります。submit()

于 2013-02-22T20:19:06.260 に答える
0

jdk の「可変」サイズのスレッド プール機能は少し注意が必要です。基本的に、使用しているセットアップは、概説した理由によりうまく機能しません。可変サイズのスレッド プールが必要な場合は、通常、次のセットアップを使用します。

   ThreadPoolExecutor executor = new ThreadPoolExecutor(maxPoolSize, maxPoolSize,
                                                         DEFAULT_THREAD_TIMEOUT, DEFAULT_THREAD_TIMEOUT_UNIT,
                                                         new LinkedBlockingQueue<Runnable>(),
                                                         threadFactory);
    executor.allowCoreThreadTimeOut(true);

これにより、1 から maxPoolSize スレッドの間で変化する可変サイズのスレッド プールが作成されます。コア サイズは最大サイズと同じであるため、プールは常にスレッドをキューに追加することを優先するため、スレッド数が最大になるまでキューをバックアップすることはありません。

更新: ハングしているタスクの問題については、タスクの長さに上限がある場合、別のマネージャーに未処理の Future を追跡させ、最大実行時間を超えている場合はキャンセルすることができます。もちろん、これはタスクが中断可能であることを前提としています。

于 2013-02-22T20:24:37.587 に答える