如何在 FutureTask 中捕获异常

在发现在Java 1.6(以及从Eclipse)上运行会吞噬方法中的异常之后,我试图想出一种方法来捕获这些异常,而无需在我的所有实现中添加 throw/catch。FutureTaskExecutors.newCachedThreadPool()Runnable.run()Runnable

API 建议重写应该有助于实现以下方面:FutureTask.setException()

导致此未来报告以给定可抛出的实例作为其原因的执行异常,除非此未来已被设置或已被取消。此方法在计算失败时由 run 方法在内部调用。

但是,此方法似乎没有被调用(使用调试器运行显示异常被 捕获,但未被调用)。我已经编写了以下程序来重现我的问题:FutureTasksetException

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.UncaughtExceptionHandlerFutureTask


答案 1

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

答案 2

你有没有试过使用UncaughtExceptionHandler

  • 您需要实现 UncaughtExceptionHandler 接口。
  • 若要设置 for 池线程,请在调用中提供线程网站。UncaughtExceptionHandlerExecutor.newCachedThreadPool(ThreadFactory)
  • 您可以通过以下方式为创建的线程设置 UncaughtExceptionHandlersetUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)

使用 ExecutorService.execute 提交任务,因为只有从随 提交的任务引发的异常才会进入未捕获的异常处理程序。对于使用 ExecutorService.submit 提交的任务,任何抛出的异常都被视为任务返回值的一部分。如果随 submit 一起提交的任务终止并出现异常,则在调用 Future.get 时会将其重新推翻,并包装在executeExecutionException


推荐