ThreadPoolExecutor ポリシー
-
26-09-2019 - |
質問
ThreadPoolExecutor を使用してタスクをスケジュールしようとしていますが、そのポリシーでいくつかの問題が発生します。記載されている動作は次のとおりです。
- corePoolSize よりも少ないスレッドが実行されている場合、Executor はキューに入れるよりも常に新しいスレッドを追加することを優先します。
- corePoolSize 以上のスレッドが実行されている場合、Executor は常に、新しいスレッドを追加するのではなく、リクエストをキューに入れることを優先します。
- リクエストをキューに入れることができない場合は、maximumPoolSize を超えない限り、新しいスレッドが作成されます。この場合、タスクは拒否されます。
私が望む動作はこれです:
- 同上
- corePoolSize を超え、maximumPoolSize 未満のスレッドが実行されている場合、キューイングよりも新しいスレッドの追加が優先され、新しいスレッドの追加よりもアイドル状態のスレッドの使用が優先されます。
- 同上
基本的に、私はどのタスクも拒否されたくありません。それらを無制限のキューに入れたいと考えています。ただし、maximumPoolSize までのスレッドが必要です。無制限のキューを使用すると、coreSize に達した後はスレッドが生成されません。境界付きキューを使用すると、タスクが拒否されます。これを回避する方法はありますか?
私が今考えているのは、SynchronousQueue 上で ThreadPoolExecutor を実行することですが、タスクを直接それにフィードするのではなく、代わりに別の無制限の LinkedBlockingQueue にタスクをフィードすることです。次に、別のスレッドが LinkedBlockingQueue から Executor にフィードし、1 つが拒否された場合は、拒否されなくなるまで再試行します。ただし、これは面倒でちょっとしたハックのように思えますが、これを行うよりクリーンな方法はあるのでしょうか?
解決
ご利用の場合は完全に合法的な、もう1つは期待よりも、残念ながら多くの困難、一般的です。背景情報については、あなたがこの議論する noreferrer"> こちらへのポインタ。シェイのソリューションは、罰金に動作します。
一般的に私は無制限のキュービット警戒すると思います。それは優雅に劣化するとは、いずれかの生産や消費者を圧倒しないように、現在の/残りの作業の比率を調節していることを明示的に入ってくるフロー制御を持っている方が良いでしょう。
他のヒント
これはおそらく要求されているように、マイクロ・管理するスレッドプールには必要ありません。
また、潜在的に無制限の同時実行スレッドを可能にしながら、Aは、スレッドプールを再使用するアイドル状態のスレッドをキャッシュされました。もちろんこれは、バースト的な期間でのオーバーヘッドのコンテキスト切り替えから暴走パフォーマンスの劣化につながる可能性があります。
Executors.newCachedThreadPool();
より良いオプションは、アイドル状態のスレッドが最初に使用される保証の概念を廃棄しながら、スレッドの合計数に制限を置くことです。構成の変更は以下のようになります:
corePoolSize = maximumPoolSize = N;
allowCoreThreadTimeOut(true);
setKeepAliveTime(aReasonableTimeDuration, TimeUnit.SECONDS);
それは非常に忙しくしてはならないよりも、エグゼキュータは、以下corePoolSize
スレッドを持っている場合、このシナリオ上の理由。システムは非常に混雑していない場合は、新しいスレッドをスピンアップにはほとんど害があります。これを行うと、それが許可され、労働者の最大数の下であれば、あなたのThreadPoolExecutor
は常に新しいワーカーを作成します。労働者の最大数は、労働者が仕事のためにぼんやりと待っているだろう「実行すると、」タスクが与えられている場合のみです。作業員が待機タスクなしaReasonableTimeDuration
場合、終了することが許可されています。 (すべての後に、唯一の非常に多くのCPUがあります)プールサイズのための合理的な制限を使用して合理的に大きなタイムアウトが(不終端からのスレッドを維持するために)、所望の利益がありそう見られます。
最後のオプションはハックです。基本的には、ThreadPoolExecutor
は内部キューが容量を持っているかどうかを判断するためにBlockingQueue.offer
を使用しています。 BlockingQueue
のカスタム実装は常にoffer
の試みを拒否できます。 ThreadPoolExecutor
がキューにタスクをoffer
に失敗した場合、それは新しいワーカーを作成しようとします。新しいワーカーを作成することができない場合は、RejectedExecutionHandler
が呼び出されます。その時点で、カスタムRejectedExecutionHandler
は、カスタムput
にBlockingQueue
を強制することができます。
/** Hackish BlockingQueue Implementation tightly coupled to ThreadPoolexecutor implementation details. */
class ThreadPoolHackyBlockingQueue<T> implements BlockingQueue<T>, RejectedExecutionHandler {
BlockingQueue<T> delegate;
public boolean offer(T item) {
return false;
}
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
delegate.put(r);
}
//.... delegate methods
}
ただ、セットcorePoolsize = maximumPoolSize
とアンバウンド形式のキューを使用していますか?
、1を除く2、corePoolSize
は常に少ないこと又はmaximumPoolSize
と等しいからである。
編集
何をしたいと何TPEはあなたを提供するとの何かの互換性がありませんが、まだあります。
あなたがアンバウンド形式のキューを持っている場合は、あなたが観察されるようにが、maximumPoolSize
がこれまでに作成され、使用されますcorePoolSize
スレッドを超えない、ので、無視されます。
corePoolsize = maximumPoolSize
を取る場合は、だから、もう一度、あなたはありません、あなたが望むものを持っていますか?
あなたはより多くのキャッシュされたスレッドプールのようなものを探しているのだろうか?