为什么在ThreadPoolExecutor的afterExecute()中异常为null?

Kaa*_*rde 10 java multithreading futuretask threadpool threadpoolexecutor

我想处理ThreadPoolExecutor#afterExecute()方法中工作线程抛出的exeptions .目前我有这个代码:

public class MyExecutor extends ThreadPoolExecutor {

    public static void main(String[] args) {
        MyExecutor threadPool = new MyExecutor();
        Task<Object> task = new Task<>();
        threadPool.submit(task);
    }

    public MyExecutor() {
        super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(4000));
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        System.out.println("in afterExecute()");
        if (t != null) {
            System.out.println("exception thrown: " + t.getMessage());
        } else {
            System.out.println("t == null");
        }
    }

    private static class Task<V> implements Callable<V> {

        @Override
        public V call() throws Exception {
            System.out.println("in call()");
            throw new SQLException("testing..");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我运行代码,我得到输出:

in call()
in afterExecute()
t == null
Run Code Online (Sandbox Code Playgroud)

为什么参数Throwable t nullafterExecute()?不应该是SQLException实例吗?

Tun*_*aki 9

这实际上是预期的行为.

引用afterExecuteJavadoc:

如果为非null,则Throwable是未捕获的RuntimeException或Error,导致执行突然终止.

这意味着Throwable实例会RuntimeException或者Error,检查Exception.由于SQLException是一个经过检查的异常,因此不会传递给它afterExecute.

这里还有其他东西(仍引用Javadoc):

注意:当操作被FutureTask显式地或通过诸如submit之类的方法包含在任务(例如)中时,这些任务对象会捕获并维护计算异常,因此它们不会导致突然终止,并且内部异常不会传递给此方法.

在您的示例中,FutureTask由于您要提交a Callable,因此任务包含在a中,因此您就是这种情况.即使在你改变你的代码投掷RuntimeException,如果不会给afterExecute.Javadoc提供了一个示例代码来处理这个,我在这里复制,以供参考:

protected void afterExecute(Runnable r, Throwable t) {
     super.afterExecute(r, t);
     if (t == null && r instanceof Future) {
       try {
         Object result = ((Future) r).get();
       } catch (CancellationException ce) {
           t = ce;
       } catch (ExecutionException ee) {
           t = ee.getCause();
       } catch (InterruptedException ie) {
           Thread.currentThread().interrupt(); // ignore/reset
       }
     }
     if (t != null)
       System.out.println(t);
}
Run Code Online (Sandbox Code Playgroud)