如何从Executors正确捕获RuntimeExceptions?

Joo*_*kka 43 java concurrency executor runtimeexception

假设我有以下代码:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(myRunnable);
Run Code Online (Sandbox Code Playgroud)

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

ska*_*man 56

干净的解决方法是使用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();
}
Run Code Online (Sandbox Code Playgroud)

  • 问题是future.get()是阻塞的,所以如果你想能够异步运行你的任务,那就不行了 (19认同)
  • 正如@Loic评论的那样,这个解决方案毫无用处,因为它首先打败了使用Executors的整个目的. (5认同)
  • 此外,您可能希望使用`Callable`而不是`Runnable`,那么您的任务可以抛出已检查的异常以及未选中的异常. (2认同)

Aar*_*lla 10

在另一个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));
Run Code Online (Sandbox Code Playgroud)


Bri*_*new 9

为什么不打电话ExecutorService#submit(),Future后退,然后在打电话时自己处理可能的异常Future#get()


Ada*_*ski 6

skaffman是正确的,因为使用submit是最干净的方法.另一种方法是子类化ThreadPoolExecutor和覆盖afterExecute(Runnable, Throwable).如果您遵循此方法,请确保调用execute(Runnable)而不是submit(Runnable)afterExecute不会调用.

根据API说明:

完成给定Runnable的执行后调用的方法.执行任务的线程调用此方法.如果非null,则Throwable是未被捕获的 RuntimeExceptionError导致执行突然终止.

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