FutureTaskで例外をキャッチする方法
-
30-09-2019 - |
質問
それを見つけた後 FutureTask
で実行します Executors.newCachedThreadPool()
Java 1.6(およびEclipseから)では、 Runnable.run()
方法、私はすべての人にスロー/キャッチを追加せずにこれらをキャッチする方法を考え出そうとしました Runnable
実装。
APIは、そのオーバーライドを示唆しています FutureTask.setException()
これで支援する必要があります:
この未来は、この将来がすでに設定されているか、キャンセルされていない限り、その原因として与えられたスロー可能なexecutionExceptionを報告します。この方法は、計算の障害時に実行方法によって内部的に呼び出されます。
ただし、この方法は呼ばれていないようです(デバッガーで実行すると、例外がキャッチされていることが示されています FutureTask
, 、 しかし setException
呼ばれていません)。私の問題を再現するために、次のプログラムを書きました:
public class RunTest {
public static void main(String[] args) {
MyFutureTask t = new MyFutureTask(new Runnable() {
@Override
public void run() {
throw new RuntimeException("Unchecked exception");
}
});
ExecutorService service = Executors.newCachedThreadPool();
service.submit(t);
}
}
public class MyFutureTask extends FutureTask<Object> {
public MyFutureTask(Runnable r) {
super(r, null);
}
@Override
protected void setException(Throwable t) {
super.setException(t);
System.out.println("Exception: " + t);
}
}
私の主な質問は、FutureTaskでスローされた例外をキャッチするにはどうすればよいですか?なぜそうしないのですか setException
呼ばれますか?
また、理由を知りたいです Thread.UncaughtExceptionHandler
メカニズムは使用されていません FutureTask
, 、これに理由はありますか?
解決
setException
おそらくオーバーライドのために作られたものではありませんが、ニーズが生じた場合に結果を例外に設定できるように提供されます。あなたがしたいのは、オーバーライドすることです done()
方法と結果を取得してみてください:
public class MyFutureTask extends FutureTask<Object> {
public MyFutureTask(Runnable r) {
super(r, null);
}
@Override
protected void done() {
try {
if (!isCancelled()) get();
} catch (ExecutionException e) {
// Exception occurred, deal with it
System.out.println("Exception: " + e.getCause());
} catch (InterruptedException e) {
// Shouldn't happen, we're invoked when computation is finished
throw new AssertionError(e);
}
}
}
他のヒント
を使用してみましたか UncaughtExceptionHandler
?
- 実装する必要があります
UncaughtExceptionHandler
インターフェース。 - 設定する
UncaughtExceptionHandler
プールスレッドの場合は、aを提供しますThreadFactory
の中にExecutor.newCachedThreadPool(ThreadFactory)
電話。 - 作成されたスレッドのUncaughexceptionHandlerを介して設定できます
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
でタスクを送信します ExecutorService.execute
, 、提出されたタスクからスローされた例外のみが execute
無作法な例外ハンドラーに到達します。提出されたタスクの場合 ExecutorService.submit
スローされた例外は、タスクの返品値の一部であると見なされます。送信で提出されたタスクが例外を除いて終了した場合、呼び出すときにそれはret延します Future.get
, 、に包まれています ExecutionException
はるかに優れた解決策:Java FutureTask完了チェック
あなたが電話するとき futureTask.get()
計算の結果を取得するために、基礎となる場合、例外(executionException)がスローされます Runnable
/Callable
例外を投げました。
ExecutionException.getCause()
その例外を返します Runnable
/Callable
投げた。
また、それが別の例外をスローします Runnable
/Callable
キャンセルされた。
のソースコードを見ました FutureTask
そして、どこで見つけることができませんでした setException
呼ばれています。
あります innerSetException
からの方法 FutureTask.Sync
(の内部クラス FutureTask
)それはanの場合に呼び出されています Throwable
実行方法によって投げられる。この方法も呼び出されています setException
.
したがって、Javadocが正しくない(または理解するのが非常に難しい)ように縫い目があります。
3つの標準的な方法と1つの即興の方法があります。 1. uncedexceptionhandlerを使用し、作成されたスレッドのcoutexceptionhandlerを設定します。
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable ex) {..}}
*しかし、制限はスレッドで投げられる例外をキャッチすることですが、将来のタスクの場合、それは飲み込まれます。 2.使用します afterExecute
この目的のために特別に提供されているフックを使用してカスタムスレッドプールエクセクターを作成した後。 shoodpoolexecutorのコードを調べて、submit> executeを介して(workqueueがあります、 workQueue.offer
)、タスクが作業キューに追加されます
final void runWorker(Worker arg0) {
Thread arg1 = Thread.currentThread();
Runnable arg2 = arg0.firstTask;
..
while(arg2 != null || (arg2 = this.**getTask()**) != null) {
arg0.lock();
..
try {
this.beforeExecute(arg1, arg2);
Object arg4 = null;
try {
arg2.run();
} catch (RuntimeException arg27) {
..
} finally {
this.**afterExecute**(arg2, (Throwable)arg4);
}
}
getTask() {..
this.workQueue.**poll**();
..}
次に、3つ目はコールメソッド内で単純なトライキャッチを使用することですが、ここで例外をキャッチすることはできません。
回避策は、呼び出し資金をリリースする工場であるTaskFactoryの呼び出しメソッドからすべての呼び出しメソッドを呼び出しています。