在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
使用,是否有任何理由?
答案 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)
使用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
的位置。
innerSetException
(FutureTask.Sync
的内部类)中存在FutureTask
方法,在run方法抛出Throwable
的情况下调用该方法。此方法也在setException
中调用
所以像javadoc这样的接缝不正确(或者很难理解......)。