ThreadPoolExecutor についてこのかなり単純な質問があります。次の状況があります。キューからオブジェクトを消費し、それらに適切なワーカータスクを作成して、ThreadPoolExecutorに送信する必要があります。これは非常に簡単です。ただし、シャットダウンシナリオ内では、多くのワーカーが実行キューに入れられる場合があります。これらのタスクの1つが1時間実行されている可能性があり、アプリケーションを比較的高速で正常にシャットダウンする必要があるため、既に処理中のタスクは正常に完了する必要がある一方で、キューに入れられたすべてのタスクをThreadPoolExecutorから破棄します。
ThreadPoolExecutorのドキュメントには remove() メソッドがありますが、削除できるのは特定のタスクのみです。 purge() すでにキャンセルされた将来のタスクに対してのみ機能します。私のアイデアは、キューに入れられたすべてのタスクを保持しているキューをクリアすることでした。 ThreadPoolExecutorはこの内部キューへのアクセスを提供しますが、ドキュメントには次のように記載されています。
メソッドgetQueue()を使用すると、監視とデバッグを目的としてワークキューにアクセスできます。この方法を他の目的に使用することは強くお勧めしません。
したがって、このキューを取得してクリアすることはできません。また、このドキュメントの抜粋には次のように書かれています。
提供されている2つのメソッド、remove(Java.lang.Runnable)とpurge()を使用して、キューに入れられた多数のタスクがキャンセルされた場合のストレージの再利用を支援します。
どうやって?確かに、エグゼキュータに送信したすべてのタスクのリストを維持できます。シャットダウンの場合は、すべてのエントリを繰り返し処理し、remove()メソッドを使用してThreadPoolExecutorから削除します...しかし...さあ、これはこのリストを維持するためのメモリの浪費と面倒。 (たとえば、すでに実行されたタスクの削除)
ヒントや解決策に感謝します!
ExecutorServiceをラップすることを検討しましたか?作成する
CleanShutdownExecutorService implements Executor
これは、すべての呼び出しを別のエグゼキュータに委任しますが、Futuresを独自のリストに保持します。 CleanShutdownExecutorServiceは、shutdown()を呼び出すcancelRemainingTasks()メソッドを持ち、リスト内のすべてのFuturesでcancel(false)を呼び出すことができます。
以前は、スレッドが長時間実行されているアプリで作業していました。これはシャットダウン時に行いますが、
BlockingQueue<Runnable> queue = threadPool.getQueue();
List<Runnable> list = new ArrayList<Runnable>();
int tasks = queue.drainTo(list);
リストはファイルに保存されます。起動時にリストがプールに追加されるため、ジョブが失われることはありません。
ExecutorService.shutdown() が十分に機能しておらず、 ExecutorService.shutdownNow() が多すぎるため、途中で何かを書く必要があると思います。送信したものをすべて覚えておいてください。タスクを呼び出し、shutdown()
を呼び出した後(または前)に手動で削除します。
これは古い質問ですが、これが他の誰かに役立つ場合に備えて、shutdown()を呼び出すときに揮発性ブール値を設定し、そのブール値が実際に開始する前に設定されている場合は、送信された各タスクを終了させることができます。これにより、実際に開始したタスクは完了できますが、キューに入れられたタスクは実際のアクティビティを開始できなくなります。
ボンベの答えはまさにあなたが望むものです。 shutdownNow()
は、nuke and paveアプローチを使用してすべてを停止します。これは、使用しているThreadPoolExecutor
の実装をサブクラス化する以外に、実行できる最善の方法です。
allowCoreThreadTimeOut(true);
を試すことができます
独自のタスクキューを作成して、それをThreadPoolExecutor
コンストラクターに渡すことができます。
int poolSize = 1; // number of threads
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>();
Executor executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue);
コードのどこかでキューをクリアすると、残りのタスクは実行されません。
queue.clear();
スレッドプールにシャットダウンするように指示します。getQueue、for-各結果を個別のRunnableに入れ、removeメソッドを使用して各Runnableを削除します。キューのタイプによっては、戻り値に基づいて削除を早期に停止できる場合があります。
基本的に、これはキューを取得してクリアすることであり、機能するメソッドを介してのみクリアします。すべての送信を手動で記憶する代わりに、スレッドプールがすでにすべての送信を記憶している必要があるという事実を使用します。ただし、ライブビューだと思うので、おそらくキューの防御コピーを作成する必要があります。したがって、ライブビューを繰り返し/繰り返し実行している場合、削除すると同時変更例外が発生する可能性があります。
動作する可能性のあるクレイジーで汚れた解決策(実際に考え抜かれたりテストされたりしていない)は、WorkerTasksのinterrupt()
を上書きすることです。これは、interrupt()
がshutdownNow()によってそれらを呼び出しました。
これでshutdownNow()
を使用できるようになりますか?
シャットダウン後にawaitTermination(long timeout, TimeUnit unit)
が機能しませんか?
executor.shutdown(); executor.awaitTermination(60、TimeUnit.SECONDS)