如何从Executors正确捕获RuntimeExceptions?

时间:2009-11-06 14:30:47

标签: java concurrency executor runtimeexception

说我有以下代码:

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

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

5 个答案:

答案 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的任务(RunnableThreadPoolExecutors)将转换为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);
            }
        }
        ...
    }

如果你想捕捉异常:

        
      1. skaffman的回答
        
      2.当你新建一个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
            }
        }