JEE環境でのタスクスケジューリングのためにScheduledExecutorService
を取得しました。これらのタスクの中には、中断されたときにリソースが開かれているものがあります(例えば、Luceneのようなサードパーティのライブラリを開いたファイル)。ScheduledExecutorService.shutdownNow()
ScheduledExecutorServiceでスケジュールされたタスクインスタンスの取得
私はスレッドが自分自身の実行を止めることはできないことを知っています:スレッドを停止するために使用される方法は、割り込みフラグを頬を傾けてメソッドの実行を停止し、スレッドがブロック(例えばwait()、sleep )など)、または割り込み可能なチャネルでIO操作を行っている場合、Thread.interrupt()
はInterruptedException
を立ち上げます。どちらの場合も、finallyブロックを実行する必要があります。 参照:http://download.oracle.com/javase/1,5.0/docs/api/java/lang/Thread.html#interrupt%28%29。明らかに、私はすでにタスククラスのfinallyブロックでリソースを解放しようとしましたが、いくつかの環境(例えばCentOS)ではスレッドが中断したときfinallyブロックは実行されません。そして、私は公式のJavaドキュメントには、この非常にクールなノートを見つけた:
注:試してみるか、キャッチコードが実行されている間、JVMが終了した場合、 finallyブロックが実行されないことがあります。同様に、tryまたはcatchコードを実行しているスレッド が中断または終了した場合、アプリケーション全体が として継続しても、最後に ブロックが実行されないことがあります。
私が必要とするのは、リソースの解放を強制するタスククラスにいくつかのパブリックメソッドを実装するためにスケジュールされたすべてのタスクへの参照です。 ScheduledExecutorService
からタスククラスへの参照を取得できますか?または、私の問題をより良い方法で解決するための素晴らしいアイデアがありますか?
最初の解決策:それをラップしてください!
ScheduledExecutorService
のラッパークラスを作成し、このようなプロパティを追加します。それに
private IdentityHashMap<ScheduledFuture<?>, Runnable> taskList;
を私たちが直接任意のRunnableオブジェクトにアクセスする、またはそれに関連するScheduledFuture
ですることができます。ラッパーのインスタンス化のために、私はExecutors.newScheduledThreadPool()
メソッドからScheduledExecutorService
を取得し、それを私のラッパーに渡すことができます。
もう1つ解決策:それを拡張してください!
ScheduledThreadPoolExecutor
を拡張し、IdentityHashMapプロパティを追加して、ジョブのスケジュールまたはキャンセル方法をすべて上書きして、マップから参照を追加または削除します。
両方のソリューションに問題がありますか?
ラッパーまたは拡張クラスの呼び出し元がSchedulerFuture<?>
オブジェクトを受け取った場合は、「カプセル」をバイパスしてSchedulerFuture<?>.cancel()
メソッドでジョブをキャンセルすることができます。ラッパーを使用すると、呼び出し側にSchedulerFuture<?>
参照を渡すことは避けられますが、拡張クラスを使用することはできません(拡張クラスで独自のメソッドを作成すると、ラッパーと同じ結果が得られますが、非常に混乱します)。
エレガントなソリューション:独自のスケジューラ!カジュに感謝しています...
- 実際 スレッドをキャンセルするだけでなくへ
Runnable
オブジェクトを操作するのカスタムcancel()
方法を実装ScheduledFuture
インタフェース - の一の実装で
Runnable
を飾るdecorateTask()
方法 - を上書きする
ScheduledThreadPoolExecutor
を拡張リソース解放のために を強制してください。
詳細とコードの例については、postをご覧ください。
VMが終了していると思われますか? finallyブロックを実行していませんか?その場合は、すべてのタスクがキャンセルされたとき(つまり、エグゼキュータ上で終了を待って実装する)にVMを終了させるのはなぜですか?それはちょうど競争状態になる可能性があります..? – Toby
これは、Tomcatアプリケーションがシャットダウンされ、Luceneライブラリがサーバ内の共有リソースである場合に発生します。したがって、アプリケーションのすべてのスレッドはキャンセルされますが、VMはまだ生きており、ライブラリは他のWebアプリケーションに引き続き使用できます。一方、アプリケーションをシャットダウンするときは、 'awaitTermination(数分)'の後に 'shutdown()'、次に 'shutdownNow()'を実行します。問題:Luceneインデックスの再構築は非常に長いタスク(数時間)です。したがって、 'shutdownNow()'が呼び出されたときにインデックス再構築が実行されている場合、スレッドは中断されますが、リソースは解放されません。 – ggarciao
hmmm、私はluceneのバグとしてそれを上げたい!スレッドはIMOを中断するために適切に応答する必要があります(正しい中断ポリシーを実装する必要があります)。あなたはこれを回避するために非常に努力する必要があります。 – Toby