Java 如何在 FutureTask 中捕获异常
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3555302/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to catch exceptions in FutureTask
提问by Thirler
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.
发现后FutureTask
在运行Executors.newCachedThreadPool()
于Java 1.6(和Eclipse的)燕子在异常Runnable.run()
的方法,我试图想出一个方法来捕捉这些不增加投掷/捕获我所有的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. This method is invoked internally by the run method upon failure of the computation.
导致此 Future 报告一个 ExecutionException 以给定的 throwable 作为其原因,除非此 Future 已被设置或已被取消。该方法在计算失败时由 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). I've written the following program to reproduce my problem:
但是,似乎没有调用此方法(使用调试器运行显示异常被 捕获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);
}
}
My main question is: How can I catch Exceptions thrown in a FutureTask? Why doesn't setException
get called?
我的主要问题是:如何捕获 FutureTask 中抛出的异常?为什么不setException
叫?
Also I would like to know why the Thread.UncaughtExceptionHandler
mechanism isn't used by FutureTask
, is there any reason for this?
另外我想知道为什么Thread.UncaughtExceptionHandler
不使用该机制FutureTask
,有什么原因吗?
采纳答案by gustafc
setException
probably isn't made for overriding, but is provided to let you set the result to an exception, should the need arise. What you want to do is override the done()
method and try to get the result:
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);
}
}
}
回答by user85421
I have looked at the source code of FutureTask
and could not find where setException
is being called.
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. This method is also being called in setException
.
So it seams like the javadoc is not correct (or very hard to understand...).
我查看了 的源代码,FutureTask
但找不到setException
被调用的位置。
有一个innerSetException
来自FutureTask.Sync
(内部类FutureTask
)的方法被调用,以防Throwable
被 run 方法抛出。中也调用了此方法setException
。
所以它看起来像javadoc不正确(或者很难理解......)。
回答by Soundlink
Have you tried using an UncaughtExceptionHandler
?
您是否尝试过使用UncaughtExceptionHandler
?
- You need to implement the
UncaughtExceptionHandler
interface. - To set an
UncaughtExceptionHandler
for pool threads, provide aThreadFactory
in theExecutor.newCachedThreadPool(ThreadFactory)
call. - You can set the UncaughtExceptionHandler for the created thread via
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
- 您需要实现该
UncaughtExceptionHandler
接口。 - 要
UncaughtExceptionHandler
为池线程设置一个,请ThreadFactory
在Executor.newCachedThreadPool(ThreadFactory)
调用中提供一个。 - 您可以通过以下方式为创建的线程设置 UncaughtExceptionHandler
setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)
Submit the tasks with ExecutorService.execute
, because only exceptions thrown from tasks submitted with execute
make it to the uncaught exception handler. For Tasks submitted with ExecutorService.submit
any thrown exception is considered to be part of the task's return value. If a task submitted with submit terminates with an exception, it is rethrown when calling Future.get
, wrapped in an ExecutionException
用 提交任务ExecutorService.execute
,因为只有从提交的任务中抛出的异常execute
才会进入未捕获的异常处理程序。对于ExecutorService.submit
任何抛出异常提交的任务,都被视为任务返回值的一部分。如果使用 submit 提交的任务因异常终止,则在调用时重新抛出Future.get
,包装在ExecutionException
回答by Christopher Alexander
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
被取消,它也会抛出一个不同的异常。
回答by hi.nitish
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. Looking through the code of ThreadpoolExecutor, via submit > execute (there is a workQueue, workQueue.offer
), the tasks are added to the work queue
*但限制是它捕获线程抛出的异常,但在未来任务的情况下,它被吞掉。2.使用afterExecute
专门为此提供的带有钩子的自定义线程池执行器后使用。查看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.
The workaround is calling all the call methods from a call method of a TaskFactory, a factory that releases callables.
然后,第三个是在 call 方法内部使用简单的 try catch ,但您不能在这里捕获异常。
解决方法是从 TaskFactory 的调用方法调用所有调用方法,TaskFactory 是一个释放可调用对象的工厂。