如何在FutureTask中捕获异常

时间:2010-08-24 09:56:07

标签: java concurrency executorservice futuretask

在Java 1.6(以及Eclipse)中发现FutureTask中运行的Executors.newCachedThreadPool()吞噬Runnable.run()方法中的异常后,我试图找到一种方法来捕获这些没有将throw / catch添加到我的所有Runnable实现中。

API建议覆盖FutureTask.setException()应该有助于此:

  

导致此未来报告以给定throwable为原因的ExecutionException,除非已设置或已取消此Future。在计算失败时,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 个答案:

答案 0 :(得分:20)

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);
        }
    }
}

答案 1 :(得分:12)

您是否尝试使用UncaughtExceptionHandler

  • 您需要实施UncaughtExceptionHandler界面。
  • 要为池线程设置UncaughtExceptionHandler,请在Executor.newCachedThreadPool(ThreadFactory)调用中提供ThreadFactory
  • 您可以通过setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
  • 为创建的主题设置UncaughtExceptionHandler

使用ExecutorService.execute提交任务,因为只有通过execute提交的任务抛出的异常才能使其成为未捕获的异常处理程序。对于使用ExecutorService.submit提交的任务,任何抛出的异常都被视为任务返回值的一部分。如果使用submit提交的任务以异常终止,那么在调用Future.get时会重新抛出该任务,并包含在ExecutionException

答案 2 :(得分:9)

更好的解决方案: Java FutureTask completion check

当你调用futureTask.get()来检索计算结果时,如果基础Runnable / Callable引发异常,它将抛出异常(ExecutionException)。

ExecutionException.getCause()将返回Runnable / Callable投掷的异常。

如果Runnable / Callable被取消,它也会抛出不同的异常。

答案 3 :(得分:2)

我查看了FutureTask的源代码,找不到调用setException的位置。
innerSetExceptionFutureTask.Sync的内部类)中存在FutureTask方法,在run方法抛出Throwable的情况下调用该方法。此方法也在setException中调用 所以像javadoc这样的接缝不正确(或者很难理解......)。