ThreadPoolExecutorに送信されたタスクが長時間実行されているシナリオがあります。スレッドプールが開始されると、コアプールサイズ= 5、最大プールサイズ= 20、キューサイズ10で開始します。このアプリケーションでは、約10個のタスクが送信されます。ほとんどの場合、これらのタスクは数分/時間実行されてから完了します。ただし、5つのタスクすべてがI/Oでハングする状況がありました。その結果、コアプールのサイズは最大に達しましたが、Threadpoolexecutorキューがいっぱいではありませんでした。したがって、追加の5つのタスクを実行する機会はありませんでした。そのようなシナリオをどのように処理できるかを提案してください。そのような状況では、キューを小さくする方が良いオプションですか? threadPoolを初期化する際の最適なキューサイズはどれくらいですか?
また、ハングしたタスクに関して、スレッドプールからスレッドを引き出す方法はありますか?その場合、少なくとも他のタスクを実行する機会が得られます。
全体的な状況は次のようになります。
core pool size = 5,
max pool size = 20 and
queue size of 10
10個のタスクが送信されます。そのうち
したがって、あなたのプログラムはハングします。
ThreadPoolExecutor
watch here のダイナミクスについて詳しく知るには。このドキュメントの注目すべき点は次のとおりです。
[〜#〜]編集[〜#〜]
コアプールサイズを増やしたい場合は、setCorePoolSize(int corePoolSize)を使用できます。 corepoolsize
を増やすと、必要に応じて、キューに入れられたタスクを実行するために新しいスレッドが開始されます。
ThreadPoolExecutorのJavadoc 状態:
送信されたタスクを転送および保持するために、任意のBlockingQueueを使用できます。このキューの使用は、プールのサイズ設定と相互作用します。
5つのスレッドが「ハング」した後でキューサイズを超えない限り、それ以上のスレッドを取得することはありません。
本当の答えは、スレッドがハングする原因となっている問題を修正することです。それ以外の場合は、submit()
によって返されるFuture
sを使用して、スレッドの実行時間が長すぎる場合にスレッドをキャンセルするスキームを実装する必要があります。
別のアプローチは、キューで待機しているタスクの数に基づいてcorePoolSizeを設定することだと思います。 setCorePoolSizeを使用してcorePoolSizeを制御できます。サンプルモニタースレッドは、threadPoolExecutorを制御できます。このモニターを改善して、並列度を調整することもできます。
public class ExecutorMonitor extends Thread{
ThreadPoolExecutor executor = null;
int initialCorePoolSize;
public ExecutorMonitor(ThreadPoolExecutor executor)
{
this.executor = executor;
this.initialCorePoolSize = executor.getCorePoolSize();
}
@Override
public void run()
{
while (true)
{
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (executor.getQueue().size() > 0)
{
if(executor.getActiveCount() < executor.getMaximumPoolSize())
executor.setCorePoolSize(executor.getCorePoolSize() + 1);
}
if (executor.getQueue().size() == 0)
{
if(executor.getCorePoolSize() > initialCorePoolSize)
executor.setCorePoolSize(executor.getCorePoolSize() -1);
}
}
}
}
Jdkの「可変」サイズのスレッドプール機能は少し注意が必要です。基本的に、使用しているセットアップは、概説した理由によりうまく機能しません。可変サイズのスレッドプールが必要な場合、通常は次の設定を使用します。
ThreadPoolExecutor executor = new ThreadPoolExecutor(maxPoolSize, maxPoolSize,
DEFAULT_THREAD_TIMEOUT, DEFAULT_THREAD_TIMEOUT_UNIT,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
executor.allowCoreThreadTimeOut(true);
これにより、1スレッドとmaxPoolSizeスレッドの間で変化する可変サイズのスレッドプールが作成されます。コアサイズは最大サイズと同じであるため、プールは常にキューイングよりもスレッドの追加を優先します。したがって、スレッド数が最大になるまでキューをバックアップすることはありません。
更新:ハングタスクの問題については、タスクの長さに上限がある場合、別のマネージャーに未処理のFutureを追跡させ、最大実行時間を超えている場合はキャンセルすることができます。もちろん、これはタスクが中断可能であることを前提としています。
基本的な問題は、ユーザーが実際に無制限のキューシナリオでCORE_POOL_SIZEスレッドを取得していることです。そのため、コアプールに5つのスレッドがあり、それが彼が使用できるすべてである場合、最大サイズは何の役にも立ちません。すべての場合にスレッド実行の時間を短縮することをお勧めしますが、本番シナリオでは、サードパーティサービスの動作を制御できないことが多いため、解決策はコアプールサイズを最大プールサイズと等しくするか、キューサイズを制限することです。 。