如何在FutureTask中捕获异常
-
30-09-2019 - |
题
发现之后 FutureTask
运行在一个 Executors.newCachedThreadPool()
Java 1.6(以及 Eclipse)中的吞下异常 Runnable.run()
方法,我试图想出一种方法来捕获这些,而不添加 throw/catch 到我的所有 Runnable
实施。
API 建议重写 FutureTask.setException()
应该对此有所帮助:
导致此 Future 报告 ExecutionException,并以给定的 throwable 作为其原因,除非此 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
, ,这有什么原因吗?
解决方案
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);
}
}
}
其他提示
您是否尝试过使用 UncaughtExceptionHandler
?
- 您需要实施
UncaughtExceptionHandler
界面。 - 设置一个
UncaughtExceptionHandler
对于泳池线程,提供一个ThreadFactory
在里面Executor.newCachedThreadPool(ThreadFactory)
称呼。 - 您可以通过通过
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
提交任务 ExecutorService.execute
, ,因为只有从提交的任务中提出的例外 execute
求助于未被发达的例外处理程序。对于提交的任务 ExecutorService.submit
任何抛出的例外都被认为是任务返回值的一部分。如果与提交终端提交的任务有例外 Future.get
, ,包裹 ExecutionException
一个更好的解决方案:Java FutureTask 完成检查
你打电话时 futureTask.get()
要检索计算结果,如果底层存在,它将抛出异常(ExecutionException) Runnable
/Callable
抛出异常。
ExecutionException.getCause()
将返回异常 Runnable
/Callable
扔了。
如果 Runnable
/Callable
取消了。
我看了看的源代码 FutureTask
找不到哪里 setException
被称为。
有一个 innerSetException
方法 FutureTask.Sync
(内部阶级 FutureTask
)被称为 Throwable
被运行方法抛出。此方法也被调用 setException
.
因此,它像Javadoc这样的接缝不正确(或很难理解...)。
有三种标准的方式和一种即兴的方法。 1.使用unnucaughtexceptionHandler,将创建线程的unnewtexceptionHandler设置为
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable ex) {..}}
*但是限制是它抓住了线程所抛出的例外,但如果将来任务,它被吞噬了。 2.使用 afterExecute
在制作了带有钩子的自定义螺纹Poolexecutor之后,该挂钩专门为此目的提供了。查看threadpoolexecutor的代码,通过提交> execute(有一个工作形, 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**();
..}
然后,第三个是在呼叫方法中使用简单的尝试捕获,但是您无法在此处捕获异常。
解决方法正在从taskfactory的调用方法中调用所有调用方法,该方法是释放可销售物的工厂。