Java 如何在FutureTask中捕获异常
在发现Java 1.6(以及Eclipse)上运行的Java 如何在FutureTask中捕获异常,java,concurrency,executorservice,futuretask,Java,Concurrency,Executorservice,Futuretask,在发现Java 1.6(以及Eclipse)上运行的Executors.newCachedThreadPool()中的FutureTask吞噬了Runnable.run()方法中的异常后,我试图找到一种方法来捕获这些异常,而不向所有Runnable实现添加throw/catch API建议重写FutureTask.setException()应该有助于: 导致此未来报告ExecutionException,并将给定的throwable作为其原因,除非已设置或已取消此未来。当计算失败时,run方法
Executors.newCachedThreadPool()
中的FutureTask
吞噬了Runnable.run()
方法中的异常后,我试图找到一种方法来捕获这些异常,而不向所有Runnable
实现添加throw/catch
API建议重写FutureTask.setException()
应该有助于:
导致此未来报告ExecutionException,并将给定的throwable作为其原因,除非已设置或已取消此未来。当计算失败时,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);
}
}
公共类运行测试{
公共静态void main(字符串[]args){
MyFutureTask t=新建MyFutureTask(新建可运行(){
@凌驾
公开募捐{
抛出新的RuntimeException(“未检查的异常”);
}
});
ExecutorService=Executors.newCachedThreadPool();
服务提交(t);
}
}
公共类MyFutureTask扩展了FutureTask{
公共MyFutureTask(可运行的r){
super(r,null);
}
@凌驾
受保护的无效集合异常(可丢弃的t){
super.setException(t);
System.out.println(“异常:+t”);
}
}
我的主要问题是:如何捕获FutureTask中抛出的异常?为什么setException
没有被调用
另外,我想知道为什么
FutureTask
没有使用Thread.UncaughtExceptionHandler
机制,有什么原因吗?我查看了FutureTask
的源代码,但找不到调用setException
的位置。当run方法抛出可丢弃的
时,将调用来自FutureTask.Sync
(FutureTask
的内部类)的innerSetException
方法。此方法也在setException
中调用因此,javadoc是不正确的(或者很难理解…。
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);
}
}
}
公共类MyFutureTask扩展了FutureTask{
公共MyFutureTask(可运行的r){
super(r,null);
}
@凌驾
受保护的void done(){
试一试{
如果(!isCancelled())get();
}捕获(执行例外){
//发生异常,请处理它
System.out.println(“异常:+e.getCause());
}捕捉(中断异常e){
//不应该发生,我们在计算完成时被调用
抛出新断言错误(e);
}
}
}
您是否尝试过使用密码
- 您需要实现接口
- 要为池线程设置
,请在UncaughtExceptionHandler
调用中提供李>Executor.newCachedThreadPool(ThreadFactory)
- 您可以通过
setUncaughtExceptionHandler(thread.UncaughtExceptionHandler eh)
execute
提交的任务引发的异常才会进入未捕获异常处理程序。对于提交了任何抛出异常的任务,异常被视为任务返回值的一部分。如果使用submit提交的任务在异常情况下终止,则在调用时将重新启动该任务,并将其包装在ExecutionException
一个更好的解决方案中:
调用futureTask.get()
检索计算结果时,如果基础Runnable
/Callable
引发异常,则会引发异常(ExecutionException)
ExecutionException.getCause()
将返回Runnable
/Callable
引发的异常
如果
可运行的
/可调用的
被取消,它也会抛出不同的异常。有三种标准方法和一种临时方法。
1.使用UncaughtExceptionHandler,将所创建线程的UncaughtExceptionHandler设置为
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable ex) {..}}
*但其局限性在于它捕获线程抛出的异常,但在将来的任务中,它会被吞并。
2.制作带有专门为此目的提供的挂钩的自定义threadpoolexecutor后,请使用afterExecute
。查看ThreadpoolExecutor的代码,通过提交>执行(有一个工作队列,workQueue.offer
),任务被添加到工作队列中
final void runWorker(Worker arg0) {
Thread arg1 = Thread.currentThread();
Runnable arg2 = arg0.firstTask;
..
while(arg2 != null || (arg2 = this.**getTask()**) != null) {
arg0.lock();
..
try {
this.beforeExecute(arg1, arg2);
Object arg4 = null;
try {
arg2.run();
} catch (RuntimeException arg27) {
..
} finally {
this.**afterExecute**(arg2, (Throwable)arg4);
}
}
getTask() {..
this.workQueue.**poll**();
..}
在进一步研究了速度非常慢的sun bugs数据库之后:很明显,它自2006年就被发现了,但仍然没有被修复(尽管它被声明为已修复)@Thirler-bug报告清楚地表明它在Java 7中得到了修复。
setException
得到了很好的使用。我复制并粘贴了你的代码,效果很好。在对任务调用get()
方法时,您可能还希望尝试执行ExecutionException
的try-catch。使用Callable/Future组合的方法是错误的。future.get()方法为您提供了封装在ExecutionException中的异常。捕捉得好!我使用的是执行器服务。提交错误。如何从ExecutionExc中提取状态代码