45

次のコードがあるとします。

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);

myRunnableがをスローした場合、どうすればRuntimeExcpetionそれをキャッチできますか? 1 つの方法は、独自のThreadFactory実装を提供し、そこから出てくる s のnewSingleThreadExecutor()カスタムuncaughtExceptionHandlers を設定することです。Threadもう 1 つの方法は、try-catch ブロックを含むmyRunnableローカル (匿名) にラップすることです。Runnable他にも同様の回避策があるかもしれません。でも…なんだか汚い感じがして、こんなに複雑にならないように感じます。きれいな解決策はありますか?

4

5 に答える 5

58

クリーンな回避策は、ExecutorService.submit()の代わりに使用することですexecute()。これFutureにより、タスクの結果または例外を取得するために使用できる が返されます。

ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
  public void run() {
    throw new RuntimeException("foo");
  }
};

Future<?> future = executor.submit(task);
try {
  future.get();
} catch (ExecutionException e) {
  Exception rootException = e.getCause();
}
于 2009-11-06T14:53:36.653 に答える
11

ランタイム例外をキャッチして処理する別のランナブルでランナブルをデコレートします。

public class REHandler implements Runnable {
    Runnable delegate;
    public REHandler (Runnable delegate) {
        this.delegate = delegate;
    }
    public void run () {
        try {
            delegate.run ();
        } catch (RuntimeException e) {
            ... your fancy error handling here ...
        }
    }
}

executor.execute(new REHandler (myRunnable));
于 2009-11-06T15:02:35.063 に答える
9

ExecutorService#submit()を呼び出して、バックを取得し、Future呼び出し時に発生する可能性のある例外を自分で処理してみませんFuture#get()か?

于 2009-11-06T14:48:32.187 に答える
6

submitusing が最もクリーンなアプローチであるという点で、skaffman は正しいです。別のアプローチは、サブクラス化ThreadPoolExecutorしてオーバーライドすることafterExecute(Runnable, Throwable)です。このアプローチに従う場合は、呼び出されるか呼び出されないのではなく、必ず呼び出してexecute(Runnable)ください。submit(Runnable)afterExecute

API の説明によると:

指定された Runnable の実行が完了すると呼び出されるメソッド。このメソッドは、タスクを実行したスレッドによって呼び出されます。null 以外の場合、Throwable はキャッチ されていないRuntimeExceptionError、実行が突然終了した原因です。

注: アクションがタスク (FutureTask など) に明示的に、または submit などのメソッドを介して囲まれている場合、これらのタスク オブジェクトは計算上の例外をキャッチして保持するため、突然終了することはなく、内部例外はこのメソッドに渡されません。 .

于 2009-11-06T14:58:53.247 に答える
2

に送信された task(CallableまたはRunnable)ThreadPoolExecutorsは に変換され、送信した taskと同じFuturnTaskという名前の prop が含まれます。callableFuturnTask には以下のような独自のrunメソッドがあります。スローされたすべての例外またはスロー可能なc.call()ものはキャッチされ、という名前の小道具に入れられoutcomeます。FuturnTask のgetメソッドを呼び出すと、スローoutcomeされます

FuturnTask.run Jdk1.8 ソース コードから

public void run() {
        ...
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // save ex into `outcome` prop
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        }
        ...
    }

例外をキャッチしたい場合:

      1.スカフマンの答え
      2. ThreadPoolExecutor を新規作成するときに `afterExecute` を上書きする
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            Throwable cause = null;
            if (t == null && r instanceof Future) {
                try {
                    ((Future<?>) r).get();
                } catch (InterruptedException | ExecutionException e) {
                    cause = e;
                }
            } else if (t != null) {
                cause = t;
            }
            if (cause != null) {
                // log error
            }
        }
于 2016-08-25T11:49:00.413 に答える