31

ThreadPoolExecutorについてこのかなり単純な質問があります。次の状況があります。キューからオブジェクトを消費し、それらに適切なワーカータスクを作成して、ThreadPoolExecutorに送信する必要があります。これは非常に簡単です。ただし、シャットダウンシナリオ内では、多くのワーカーが実行キューに入れられる場合があります。これらのタスクの1つが1時間実行されている可能性があり、アプリケーションを比較的高速で正常にシャットダウンする必要があるため、既に処理中のタスクを正常に完了する必要があるときに、キューに入れられたすべてのタスクをThreadPoolExecutorから破棄します。

ThreadPoolExecutorのドキュメントにはremove()メソッドがありますが、削除できるのは特定のタスクのみです。パージ()は、すでにキャンセルされた将来のタスクに対してのみ機能します。私のアイデアは、キューに入れられたすべてのタスクを保持しているキューをクリアすることでした。ThreadPoolExecutorはこの内部キューへのアクセスを提供しますが、ドキュメントには次のように記載されています。

getQueue()メソッドを使用すると、監視とデバッグを目的としたワークキューへのアクセスが可能になります。この方法を他の目的に使用することは強くお勧めしません。

したがって、このキューを取得してクリアすることはできません。また、このドキュメントの抜粋には次のように書かれています。

提供されている2つのメソッド、remove(java.lang.Runnable)とpurge()を使用して、キューに入れられた多数のタスクがキャンセルされた場合のストレージの再利用を支援します。

どのように?確かに、エグゼキュータに送信したすべてのタスクのリストを維持できます。シャットダウンの場合は、すべてのエントリを繰り返し処理し、remove()メソッドを使用してThreadPoolExecutorから削除します...しかし...さあ、これはこのリストを維持するためのメモリの浪費と面倒。(たとえば、すでに実行されたタスクを削除する)

ヒントや解決策に感謝します!

4

10 に答える 10

14

以前は、スレッドが長時間実行されているアプリで作業していました。これはシャットダウン時に行いますが、

BlockingQueue<Runnable> queue = threadPool.getQueue();
List<Runnable> list = new ArrayList<Runnable>();
int tasks = queue.drainTo(list);

リストはファイルに保存されます。起動時にリストがプールに追加されるため、ジョブが失われることはありません。

于 2009-11-05T15:46:15.693 に答える
11

ExecutorServiceをラップすることを検討しましたか?作成する

CleanShutdownExecutorService implements Executor 

これは、すべての呼び出しを別のエグゼキュータに委任しますが、Futuresを独自のリストに保持します。CleanShutdownExecutorServiceは、shutdown()を呼び出すcancelRemainingTasks()メソッドを持ち、リスト内のすべてのFuturesでcancel(false)を呼び出すことができます。

于 2009-11-05T16:00:23.003 に答える
5

ExecutorService.shutdown()が十分に機能しておらず、ExecutorService.shutdownNow()が機能しすぎているため、途中で何かを書き留める必要があると思います。送信したすべてのタスクを覚えて、呼び出し後(または前)に手動で削除してくださいshutdown()

于 2009-11-05T10:18:30.300 に答える
5

これは古い質問ですが、これが他の誰かに役立つ場合は、shutdown()を呼び出すときに揮発性ブール値を設定し、実際に開始する前にそのブール値が設定されている場合は、送信された各タスクを終了させることができます。これにより、真に完了を開始したタスクは許可されますが、キューに入れられたタスクが実際のアクティビティを開始することはできなくなります。

于 2010-11-10T18:59:12.110 に答える
3

ThreadPoolExecutor独自のタスクキューを作成して、コンストラクターに渡すことができます。

int poolSize = 1; // number of threads
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>();
Executor executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue);

コードのどこかでキューをクリアすると、残りのタスクは実行されません。

queue.clear();
于 2018-09-18T12:50:57.197 に答える
2

ボンベの答えはまさにあなたが望むものです。核兵器と舗装のアプローチshutdownNow()を使用してすべてを停止します。これは、使用している実装をサブクラス化することを除いて、実行できる最善のことです。ThreadPoolExecutor

于 2009-11-05T12:59:20.817 に答える
1

あなたが試すことができますallowCoreThreadTimeOut(true);

于 2010-10-27T09:07:38.020 に答える
0

スレッドプールにシャットダウンするように指示します。getQueue、for-それぞれの結果を個々のRunnableに分け、removeメソッドを使用して各Runnableを削除します。キューのタイプによっては、戻り値に基づいて削除を早期に停止できる場合があります。

基本的に、これはキューを取得してクリアすることであり、機能するメソッドを介してのみクリアします。すべての送信を手動で記憶する代わりに、スレッドプールがすでにすべての送信を記憶している必要があるという事実を使用します。ただし、ライブビューであると思うので、おそらくキューの防御コピーを作成する必要があります。したがって、ライブビューを繰り返し/繰り返し実行している場合、削除すると同時変更例外が発生する可能性があります。

于 2009-11-05T13:46:00.490 に答える
0

動作する可能性のある(実際の考えやテストではない)クレイジーで汚れた解決策は、workerTasksを上書きすることです。これは、shutdownNow()によって呼び出されたinterrupt()ときに、グローバル値が設定されている場合にのみシャットダウンを拒否します。interrupt()

shutdownNow()それはあなたがnoを使用することを可能にするはずですか?

于 2009-11-05T13:19:10.330 に答える
0

awaitTermination(long timeout, TimeUnit unit)シャットダウン後に動作しませんか?

executor.shutdown(); executor.awaitTermination(60、TimeUnit.SECONDS)

于 2009-11-05T16:05:06.583 に答える