[英]How to catch exceptions in FutureTask
After finding that FutureTask
running in a Executors.newCachedThreadPool()
on Java 1.6 (and from Eclipse) swallows exceptions in the Runnable.run()
method, I've tried to come up with a way to catch these without adding throw/catch to all my Runnable
implementations. 在发现在Java 1.6(和Eclipse
Executors.newCachedThreadPool()
上的Executors.newCachedThreadPool()
运行的FutureTask
吞噬了Runnable.run()
方法中的异常之后,我试图想出一种方法来捕获这些异常而不添加throw / catch我所有的Runnable
实现。
The API suggests that overriding FutureTask.setException()
should help in this: 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.
导致此未来报告ExecutionException,并将给定的throwable作为其原因,除非已设置或已取消此Future。 This method is invoked internally by the run method upon failure of the computation.
在计算失败时,run方法在内部调用此方法。
However this method doesn't seem to be called (running with the debugger shows the exception is caught by FutureTask
, but setException
isn't called). 但是,似乎没有调用此方法(使用调试器运行显示
FutureTask
捕获异常,但未setException
)。 I've written the following program to reproduce my problem: 我写了以下程序来重现我的问题:
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);
}
}
My main question is: How can I catch Exceptions thrown in a FutureTask? 我的主要问题是:如何捕获FutureTask中引发的异常? Why doesn't
setException
get called? 为什么不调用
setException
?
Also I would like to know why the Thread.UncaughtExceptionHandler
mechanism isn't used by FutureTask
, is there any reason for this? 另外我想知道为什么
FutureTask
不使用Thread.UncaughtExceptionHandler
机制,有什么理由吗?
setException
probably isn't made for overriding, but is provided to let you set the result to an exception, should the need arise. setException
可能不是用于覆盖,而是用于在需要时将结果设置为异常。 What you want to do is override the done()
method and try to get the result: 你想要做的是覆盖
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);
}
}
}
Have you tried using an UncaughtExceptionHandler
? 您是否尝试过使用
UncaughtExceptionHandler
?
UncaughtExceptionHandler
interface. UncaughtExceptionHandler
接口。 UncaughtExceptionHandler
for pool threads, provide a ThreadFactory
in the Executor.newCachedThreadPool(ThreadFactory)
call. UncaughtExceptionHandler
,请在Executor.newCachedThreadPool(ThreadFactory)
调用中提供ThreadFactory
。 setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
为创建的线程设置UncaughtExceptionHandler Submit the tasks with ExecutorService.execute
, because only exceptions thrown from tasks submitted with execute
make it to the uncaught exception handler. 使用
ExecutorService.execute
提交任务,因为只有从使用execute
提交的任务抛出的异常才能使其成为未捕获的异常处理程序。 For Tasks submitted with ExecutorService.submit
any thrown exception is considered to be part of the task's return value. 对于使用
ExecutorService.submit
提交的任务,任何抛出的异常都被视为任务返回值的一部分。 If a task submitted with submit terminates with an exception, it is rethrown when calling Future.get
, wrapped in an ExecutionException
如果使用submit提交的任务以异常终止,则在调用
Future.get
时会Future.get
,包含在ExecutionException
A much better solution: Java FutureTask completion check 一个更好的解决方案: Java FutureTask完成检查
When you call futureTask.get()
to retrieve the result of the computation it will throw an exception (ExecutionException) if the underlying Runnable
/ Callable
threw an exception. 当调用
futureTask.get()
来检索计算结果时,如果底层Runnable
/ Callable
引发异常,它将抛出异常(ExecutionException)。
ExecutionException.getCause()
will return the exception that the Runnable
/ Callable
threw. ExecutionException.getCause()
将返回Runnable
/ Callable
抛出的异常。
It will also throw a different exception if the Runnable
/ Callable
was canceled. 如果
Runnable
/ Callable
被取消,它也会抛出一个不同的异常。
I have looked at the source code of FutureTask
and could not find where setException
is being called. 我查看了
FutureTask
的源代码,但无法找到调用setException
位置。
There is an innerSetException
method from FutureTask.Sync
(inner class of FutureTask
) that is being called in case of an Throwable
being thrown by the run method. 有一个
innerSetException
从方法FutureTask.Sync
(内部类的FutureTask
),其被称为在的情况下Throwable
由run方法抛出。 This method is also being called in setException
. 此方法也在
setException
中setException
。
So it seams like the javadoc is not correct (or very hard to understand...). 所以像javadoc这样的接缝不正确(或者很难理解......)。
There are three standard ways and one improvised way. 有三种标准方式和一种即兴方式。 1. use UncaughtExceptionHandler, set the UncaughtExceptionHandler for the created thread as
1.使用UncaughtExceptionHandler,将创建的线程的UncaughtExceptionHandler设置为
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread t, Throwable ex) {..}}
*But the limitation is it catches the exception thrown by thread but in case of future task, it is swallowed. *但是限制是它捕获线程抛出的异常,但是在未来任务的情况下,它被吞噬。 2. use
afterExecute
after making a custom threadpoolexecutor with hook that has been provided specially for this purpose. 2.在使用专门为此目的提供的钩子制作自定义threadpoolexecutor之后使用
afterExecute
。 Looking through the code of ThreadpoolExecutor, via submit > execute (there is a workQueue, workQueue.offer
), the tasks are added to the work queue 查看ThreadpoolExecutor的代码,通过submit> execute(有一个workQueue,
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**();
..}
Then, the third is using simple try catch inside the call method but you can not catch the exception outside here. 然后,第三个是在调用方法中使用简单的try catch但是你不能在这里捕获异常。
The workaround is calling all the call methods from a call method of a TaskFactory, a factory that releases callables. 解决方法是从TaskFactory的调用方法调用所有调用方法,TaskFactory是一个释放callables的工厂。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.