在发现在Java 1.6(和Eclipse)上的Executors.newCachedThreadPool()中运行的FutureTask吞噬了Runnable.run()方法中的异常之后,我试图想出一种方法来捕获这些异常而不添加throw / catch我所有的Runnable实现.
API建议覆盖FutureTask.setException()应该有助于:
Causes this future to report an ExecutionException with the given throwable as its cause, unless this Future has already been set or has been cancelled. This method is invoked internally by the run method upon failure of the computation.
但是,似乎没有调用此方法(使用调试器运行显示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?
另外我想知道为什么FutureTask不使用Thread.UncaughtExceptionHandler机制,有什么理由吗?
解决方法:
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);
}
}
}