ScheduledExecutorService
JEE環境でのタスクスケジューリング用に取得しました。これらのタスクの中には、中断されたときにリソースを開いたままにするものがありScheduledExecutorService.shutdownNow()
ます (たとえば、Lucene のようなサードパーティのライブラリでファイルを開くなど)。
スレッドはそれ自体で実行を停止できない場合があることを知っています。スレッドを停止するために使用する必要がある方法は、割り込みフラグをチークしてメソッドの実行を停止することです。スレッドがブロックされている場合 (例: wait()、sleep() など)または、割り込み可能なチャネルで何らかの IO 操作をThread.interrupt()
行うと、InterruptedException
上昇します。どちらの場合も、finally ブロックを実行する必要があります。http://download.oracle.com/javase/1,5.0/docs/api/java/lang/Thread.html#interrupt%28%29を参照してください。
明らかに、Task クラスに非常に適切に実装された finally ブロックを使用してリソースを解放しようとしましたが、一部の環境 (CentOS など) では、スレッドが中断されたときに finally ブロックが実行されません。そして、公式のJavaドキュメントで次の非常にクールなメモを見つけました。
注: try または catch コードの実行中に JVM が終了すると、finally ブロックが実行されない場合があります。同様に、try または catch コードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が続行されても、finally ブロックが実行されない可能性があります。
したがって、リソースの解放を強制する Task クラスに public メソッドを実装するために、スケジュールされたすべてのタスクへの参照が必要です。からタスク クラスへのこれらの参照を取得できますScheduledExecutorService
か? または、私の問題をより良い方法で解決するためのクールなアイデアはありますか?
最初の解決策: 包む!
のラッパー クラスを作成し、ScheduledExecutorService
次のようなプロパティを追加します。
private IdentityHashMap<ScheduledFuture<?>, Runnable> taskList;
これにより、任意の Runnable オブジェクトに直接、またはScheduledFuture
それに関連するオブジェクトにアクセスできます。ラッパーのインスタンス化のためにScheduledExecutorService
、メソッドからを取得Executors.newScheduledThreadPool()
してラッパーに渡すことができます。
別の解決策: 拡張してください!
を拡張しScheduledThreadPoolExecutor
、IdentityHashMap プロパティを追加し、ジョブをスケジュールまたはキャンセルするすべてのメソッドを上書きして、Map から参照を追加/削除します。
両方のソリューションの問題?
ラッパーまたは拡張クラスの呼び出し元がオブジェクトを受け取った場合、 「カプセル」をバイパスしてSchedulerFuture<?>
、メソッドでジョブをキャンセルできます。SchedulerFuture<?>.cancel()
ラッパーを使用すると、参照を呼び出し元に渡さないようSchedulerFuture<?>
にすることができますが、拡張クラスではできません (拡張クラスで独自のメソッドを作成すると、ラッパーと同じ結果が得られますが、非常に紛らわしい方法になります)。 .
エレガントな解決策: 独自のスケジューラー! それを指摘してくれたKajに感謝します...
- を拡張してメソッド
ScheduledThreadPoolExecutor
を上書きするdecorateTask()
- インターフェイス
Runnable
の 1 つの実装で を 装飾するScheduledFuture
cancel()
実際にスレッドをキャンセルするだけでなく、Runnable
オブジェクトを操作してリソースの解放を強制するカスタム メソッドを 1 つ実装します。
詳細とコード例については、私のブログ投稿を確認してください!!!