45

假设我有以下代码:

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

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

4

5 回答 5

58

干净的解决方法是使用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();
}
于 2009-11-06T14:53:36.653 回答
11

在另一个可捕获运行时异常并处理它们的可运行对象中装饰可运行对象:

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));
于 2009-11-06T15:02:35.063 回答
9

为什么不调用ExecutorService#submit()Future返回,然后在调用时自己处理可能的异常Future#get()

于 2009-11-06T14:48:32.187 回答
6

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

根据 API 描述:

在完成给定 Runnable 的执行时调用的方法。此方法由执行任务的线程调用。如果非空,则 Throwable 是未捕获的 RuntimeExceptionError导致执行突然终止的。

注意:当任务(如 FutureTask)显式或通过提交等方法包含操作时,这些任务对象会捕获并维护计算异常,因此它们不会导致突然终止,并且内部异常不会传递给该方法.

于 2009-11-06T14:58:53.247 回答
2

提交的任务(Callable或)将转换为 a ,包含一个名为等于您提交的任务的道具。FuturnTask 有自己的方法如下。所有抛出的异常或可抛出对象都将被捕获并放入名为. 调用 FuturnTask 的方法时,会抛出RunnableThreadPoolExecutorsFuturnTaskcallablerunc.call()outcomegetoutcome

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. 斯卡夫曼的回答
      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
            }
        }
于 2016-08-25T11:49:00.413 回答