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

时间:2015-11-17 13:51:16

标签: java multithreading threadpool threadpoolexecutor futuretask

我想处理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..");
        }
    }
}

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

in call()
in afterExecute()
t == null

为什么参数Throwable t null位于afterExecute()?它不应该是SQLException实例吗?

2 个答案:

答案 0 :(得分:8)

这实际上是预期的行为。

引用afterExecute Javadoc:

  

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

这意味着throwable实例将为RuntimeExceptionError已选中Exception。由于SQLException是已检查的例外,因此不会将其传递给afterExecute

此处还有其他事情(仍在引用Javadoc):

  

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

在您的示例中,由于您要提交FutureTask,因此任务包含在Callable中,因此您就是这种情况。即使在您更改代码时也会抛出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);
}

答案 1 :(得分:1)

这是另一种方法。从here

获取提示
package com.autonomy.introspect.service;

import java.sql.SQLException;
import java.util.concurrent.*;

public class MyExecutor extends ThreadPoolExecutor {

    public static void main(String[] args) {
        MyExecutor threadPool = new MyExecutor();
        Task<Object> task = new Task<Object>();
        Future<Object> futureTask = threadPool.submit(task);
        try {
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            System.out.println("exception thrown: " + e.getMessage());
        }
    }

    public MyExecutor() {
        super(4, 20, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(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..");
        }
    }
}

afterExecute的用法用途不同。

This class provides protected overridable beforeExecute(java.lang.Thread,
java.lang.Runnable) and afterExecute(java.lang.Runnable, 
java.lang.Throwable) methods that are called before and after execution of 
each task. These can be used to manipulate the execution environment; for 
example, reinitializing ThreadLocals, gathering statistics, or adding log 
entries. Additionally, method terminated() can be overridden to perform any 
special processing that needs to be done once the Executor has fully 
terminated.

If hook or callback methods throw exceptions, internal worker threads may 

反过来失败并突然终止。