1. ホーム

[解決済み】Java ExecutorService タスクの例外処理について

2022-04-05 04:16:53

質問

Java の ThreadPoolExecutor クラスを使用して、多数の重いタスクを一定の数のスレッドで実行します。各タスクは、例外によって失敗する可能性がある場所がたくさんあります。

をサブクラス化しました。 ThreadPoolExecutor をオーバーライドし afterExecute このメソッドは、タスクの実行中に発生したキャッチできない例外を提供することになっています。しかし、うまくいかないようです。

例えば

public class ThreadPoolErrors extends ThreadPoolExecutor {
    public ThreadPoolErrors() {
        super(  1, // core threads
                1, // max threads
                1, // timeout
                TimeUnit.MINUTES, // timeout units
                new LinkedBlockingQueue<Runnable>() // work queue
        );
    }

    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if(t != null) {
            System.out.println("Got an error: " + t);
        } else {
            System.out.println("Everything's fine--situation normal!");
        }
    }

    public static void main( String [] args) {
        ThreadPoolErrors threadPool = new ThreadPoolErrors();
        threadPool.submit( 
                new Runnable() {
                    public void run() {
                        throw new RuntimeException("Ouch! Got an error.");
                    }
                }
        );
        threadPool.shutdown();
    }
}

このプログラムの出力は、スレッドプールに提出された唯一のRunnableが例外をスローしているにもかかわらず、"Everything's fine--situation normal!"となっています。何が起こっているのか、何か手がかりはありますか?

ありがとうございます。

解決方法は?

からの ドキュメント :

注:アクションが タスク(FutureTaskなど) のようなメソッドで明示的に、あるいは サブミットする場合、これらのタスクオブジェクトはキャッチし 計算例外を保持し ので、突然の 終了し、内部 の例外が渡されることはありません。 メソッドを使用します。

Runnableを投稿すると、Futureでラップされます。

afterExecuteはこのような感じになります。

public final class ExtendedExecutor extends ThreadPoolExecutor {

    // ...

    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        if (t == null && r instanceof Future<?>) {
            try {
                Future<?> future = (Future<?>) r;
                if (future.isDone()) {
                    future.get();
                }
            } catch (CancellationException ce) {
                t = ce;
            } catch (ExecutionException ee) {
                t = ee.getCause();
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
            }
        }
        if (t != null) {
            System.out.println(t);
        }
    }
}