23

Java 1.6(およびEclipseから)でFutureTask実行するとメソッドの例外が飲み込まれることがわかった後、すべての実装にthrow/catchを追加せずにこれらをキャッチする方法を考え出そうとしました。Executors.newCachedThreadPool()Runnable.run()Runnable

FutureTask.setException()APIは、オーバーライドがこれに役立つはずであることを示唆しています。

このFutureがすでに設定されているかキャンセルされていない限り、このFutureは、指定されたthrowableを原因としてExecutionExceptionを報告します。このメソッドは、計算が失敗したときにrunメソッドによって内部的に呼び出されます。

ただし、このメソッドは呼び出されていないようです(デバッガーで実行すると、例外がによってキャッチされますが、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ですが、理由はありますか?

4

5 に答える 5

21

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);
        }
    }
}
于 2010-08-24T12:23:40.273 に答える
12

使ってみましたUncaughtExceptionHandlerか?

  • インターフェイスを実装する必要がありUncaughtExceptionHandlerます。
  • UncaughtExceptionHandlerプールスレッドのを設定するThreadFactoryには、Executor.newCachedThreadPool(ThreadFactory)呼び出しでを指定します。
  • 作成したスレッドのUncaughtExceptionHandlerは、次の方法で設定できます。setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

で送信されたタスクExecutorService.executeからスローされた例外のみexecuteがキャッチされない例外ハンドラーに到達するため、でタスクを送信します。スローされた例外で送信されExecutorService.submitたタスクの場合、タスクの戻り値の一部と見なされます。送信で送信されたタスクが例外で終了した場合、呼び出し時に再スローFuture.getされ、ExecutionException

于 2010-08-24T12:33:06.637 に答える
9

はるかに優れたソリューション: JavaFutureTask完了チェック

futureTask.get()計算結果を取得するために呼び出すと、基になるRunnable/が例外をスローした場合、例外(ExecutionException)がスローされCallableます。

ExecutionException.getCause()Runnable/がスローした例外を返しCallableます。

Runnable/Callableがキャンセルされた場合も、別の例外がスローされます。

于 2013-03-31T18:01:47.260 に答える
2

のソースコードを調べましたが、FutureTaskどこsetExceptionが呼び出されているのかわかりませんでした。runメソッドによってスローされた場合に呼び出される(の内部クラス)から
のメソッドがあります。このメソッドはで呼び出されています。 したがって、javadocが正しくない(または理解するのが非常に難しい...)ように継ぎ目があります。innerSetExceptionFutureTask.SyncFutureTaskThrowablesetException

于 2010-08-24T11:47:16.697 に答える
0

3つの標準的な方法と1つの即興の方法があります。1. UncaughtExceptionHandlerを使用し、作成されたスレッドのUncaughtExceptionHandlerを次のように設定します。

Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            public void uncaughtException(Thread t, Throwable ex) {..}}

*ただし、スレッドによってスローされた例外をキャッチするという制限がありますが、将来のタスクの場合は、飲み込まれます。2.afterExecuteこの目的のために特別に提供されたフック付きのカスタムthreadpoolexecutorを作成した後に使用します。ThreadpoolExecutorのコードを見ると、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**();
..}
  1. 次に、3つ目は、呼び出しメソッド内で単純なtry catchを使用していますが、ここでは例外をキャッチできません。

  2. 回避策は、呼び出し可能オブジェクトを解放するファクトリであるTaskFactoryの呼び出しメソッドからすべての呼び出しメソッドを呼び出すことです。

于 2018-05-23T05:04:58.900 に答える