说我有以下代码:
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);
现在,如果myRunnable
抛出RuntimeExcpetion
,我怎么能抓住它?一种方法是将我自己的ThreadFactory
实施提供给newSingleThreadExecutor()
,并为其中出现的uncaughtExceptionHandler
设置自定义Thread
。另一种方法是将myRunnable
包装到包含try-catch -block的本地(匿名)Runnable
。也许还有其他类似的解决方法。但是......不知怎的,这感觉很脏,我觉得不应该这么复杂。有干净的解决方案吗?
答案 0 :(得分:55)
干净的解决方法是使用ExecutorService.submit()
而不是execute()
。这将返回Future
,您可以使用它来检索任务的结果或例外:
ExecutorService executor = Executors.newSingleThreadExecutor();
Runnable task = new Runnable() {
public void run() {
throw new RuntimeException("foo");
}
};
Future<?> future = executor.submit(task);
try {
future.get();
} catch (ExecutionException e) {
Exception rootException = e.getCause();
}
答案 1 :(得分:9)
为什么不拨打ExecutorService#submit()
,取回Future
,然后在致电Future#get()
时自己处理可能的例外情况?
答案 2 :(得分:9)
在另一个runnable中装饰runnable,它捕获运行时异常并处理它们:
public class REHandler implements Runnable {
Runnable delegate;
public REHandler (Runnable delegate) {
this.delegate = delegate;
}
public void run () {
try {
delegate.run ();
} catch (RuntimeException e) {
... your fancy error handling here ...
}
}
}
executor.execute(new REHandler (myRunnable));
答案 3 :(得分:6)
skaffman是正确的,使用submit
是最干净的方法。另一种方法是子类ThreadPoolExecutor
并覆盖afterExecute(Runnable, Throwable)
。如果您遵循此方法请务必致电execute(Runnable)
,而不是submit(Runnable)
或afterExecute
将不会被调用。
根据API说明:
完成后调用的方法 执行给定的Runnable。这个 方法由线程调用 执行任务。如果非null,则 可怜的是未被捕获的 导致的
RuntimeException
或Error
执行突然终止。注意:当包含操作时 任务(例如FutureTask) 明确地或通过诸如的方法 提交,这些任务对象捕获和 保持计算异常,和 所以他们不会引起突然 终止,内部 例外未传递给此 方法强>
答案 4 :(得分:2)
提交给Callable
的任务(Runnable
或ThreadPoolExecutors
)将转换为FuturnTask
,其中包含名为 callable
的道具等于您提交的任务。 FuturnTask有自己的run
方法,如下所示。 c.call()
中抛出的所有异常或抛出都将被捕获并放入名为outcome
的道具中。在调用FuturnTask的get
方法时,outcome
将被抛出
FuturnTask.run来自Jdk1.8源代码
public void run() {
...
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
// save ex into `outcome` prop
setException(ex);
}
if (ran)
set(result);
}
}
...
}
如果你想捕捉异常:
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
Throwable cause = null;
if (t == null && r instanceof Future) {
try {
((Future<?>) r).get();
} catch (InterruptedException | ExecutionException e) {
cause = e;
}
} else if (t != null) {
cause = t;
}
if (cause != null) {
// log error
}
}