如何从Executors正确捕获RuntimeExceptions?

说我有以下代码:

ExecutorService executor = Executors.newSingleThreadExecutor(); executor.execute(myRunnable); 

现在,如果myRunnable抛出一个RuntimeExcpetion ,我怎么能抓住它? 一种方法是将我自己的ThreadFactory实现提供给newSingleThreadExecutor()并为其中的newSingleThreadExecutor()设置自定义的uncaughtExceptionHandler 。 另一种方法是将myRunnable包装为包含try-catch- myRunnable的本地(匿名) Runnable 。 也许还有其他类似的解决方法。 但是…不知怎的,这感觉很脏,我觉得它不应该是这么复杂。 有一个干净的解决scheme吗?

干净的解决方法是使用ExecutorService.submit()而不是execute() 。 这将返回一个Future ,您可以使用它来检索任务的结果或exception:

 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(); } 

为什么不调用ExecutorService#submit() ,在调用Future#get()时候,把Future放回去,然后自己处理可能的exception呢?

在另一个可捕获运行时exception并处理它们的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)); 

skaffman是正确的,使用submit是最干净的方法。 另一种方法是afterExecute(Runnable, Throwable) ThreadPoolExecutor并覆盖afterExecute(Runnable, Throwable) 。 如果你遵循这个方法, 一定要调用execute(Runnable)而不是submit(Runnable)否则afterExecute将不会被调用。

根据API说明:

在完成给定Runnable的执行后调用的方法。 该方法由执行任务的线程调用。 如果非null,则Throwable是未捕获的RuntimeException或导致执行突然终止的Error

注意:当任务(例如FutureTask)中明确地或通过诸如submit之类的方法将操作包含在任务中时,这些任务对象捕获和维护计算exception,因此它们不会导致突然终止,并且内部exception不会传递给此方法

提交给ThreadPoolExecutors的任务( CallableRunnable )将被转换为FuturnTask ,包含一个名为callable的道具等于您提交的任务。 FuturnTask有自己的run方法如下。 所有抛出c.call()exception或抛出将被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); } } ... } 

如果你想赶上例外:

      1. skaffman的回答
      2.当您新build一个ThreadPoolExecutor时,覆盖`afterExecute`
  @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 } }