在发现 Executors.newCachedThreadPool()
在Java 1.6上运行 Executors.newCachedThreadPool()
(以及从Eclipse中)吞下 Runnable.run()
方法中的异常之后,我试图想出一种方法来捕获这些但不向我的所有 Runnable
实现添加throw / catch .
API建议覆盖 FutureTask.setException()
应该有助于此:
使此未来报告以给定throwable为原因的ExecutionException,除非已设置或已取消此Future . 在计算失败时,run方法在内部调用此方法 .
但是这个方法似乎没有被调用(运行调试器显示异常被 FutureTask
捕获,但 setException
isn 't called). I'已写入以下程序来重现我的问题:
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
使用,这有什么理由吗?
5 回答
setException
可能不是用于覆盖,而是用于在需要时将结果设置为异常 . 你想要做的是覆盖done()
方法并尝试获得结果:你尝试过使用UncaughtExceptionHandler吗?
您需要实现UncaughtExceptionHandler接口 .
要为池线程设置
UncaughtExceptionHandler
,请在Executor.newCachedThreadPool(ThreadFactory)
调用中提供ThreadFactory .您可以通过
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
为创建的线程设置UncaughtExceptionHandler使用ExecutorService.execute提交任务,因为只有通过
execute
提交的任务抛出的异常才能使其成为未捕获的异常处理程序 . 对于使用ExecutorService.submit提交的任务,任何抛出的异常都被视为任务返回值的一部分 . 如果使用submit提交的任务以异常终止,则在调用Future.get时会重新抛出,包含在ExecutionException
中一个更好的解决方案:Java FutureTask completion check
当您调用
futureTask.get()
来检索计算结果时,如果底层Runnable
/Callable
抛出异常,它将抛出异常(ExecutionException) .ExecutionException.getCause()
将返回Runnable
/Callable
抛出的异常 .如果
Runnable
/Callable
被取消,它也会抛出不同的异常 .我查看了
FutureTask
的源代码,无法找到setException
的调用位置 .FutureTask.Sync
(内部类FutureTask
)中存在innerSetException
方法,在run方法抛出Throwable
的情况下调用该方法 . 此方法也在setException
中调用 .所以像javadoc这样的接缝不正确(或者很难理解......) .
有三种标准方式和一种即兴方式 . 1.使用UncaughtExceptionHandler,将创建的线程的UncaughtExceptionHandler设置为
*但是限制是它捕获线程抛出的异常,但是在未来任务的情况下,它被吞噬 . 2.在使用专门为此目的提供的钩子制作自定义threadpoolexecutor之后使用
afterExecute
. 查看ThreadpoolExecutor的代码,通过submit> execute(有一个workQueue,workQueue.offer
),将任务添加到工作队列中然后,第三个是在调用方法中使用简单的try catch但是你不能在这里捕获异常 .
解决方法是从TaskFactory的调用方法调用所有调用方法,TaskFactory是一个释放callables的工厂 .