如何从Executors正确捕获RuntimeExceptions?

[英]How to properly catch RuntimeExceptions from Executors?


Say that I have the following code:

假设我有以下代码:

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

Now, if myRunnable throws a RuntimeExcpetion, how can I catch it? One way would be to supply my own ThreadFactory implementation to newSingleThreadExecutor() and set custom uncaughtExceptionHandlers for the Threads that come out of it. Another way would be to wrap myRunnable to a local (anonymous) Runnable that contains a try-catch -block. Maybe there are other similar workarounds too. But... somehow this feels dirty, I feel that it shouldn't be this complicated. Is there a clean solution?

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

5 个解决方案

#1


55  

The clean workaround is to use ExecutorService.submit() instead of execute(). This returns you a Future which you can use to retrieve the result or exception of the task:

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

#2


9  

Decorate the runnable in another runnable which catches the runtime exceptions and handles them:

在另一个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


9  

Why not call ExecutorService#submit(), get the Future back and then handle possible exceptions yourself when calling Future#get() ?

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

#4


6  

skaffman is correct in that using submit is the cleanest approach. An alternative approach is to subclass ThreadPoolExecutor and override afterExecute(Runnable, Throwable). If you follow this approach be sure to call execute(Runnable) rather than submit(Runnable) or afterExecute will not be invoked.

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

Per the API description:

根据API说明:

Method invoked upon completion of execution of the given Runnable. This method is invoked by the thread that executed the task. If non-null, the Throwable is the uncaught RuntimeException or Error that caused execution to terminate abruptly.

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

Note: When actions are enclosed in tasks (such as FutureTask) either explicitly or via methods such as submit, these task objects catch and maintain computational exceptions, and so they do not cause abrupt termination, and the internal exceptions are not passed to this method.

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

#5


2  

a task(Callable or Runnable) submitted to ThreadPoolExecutors will be convert to a FuturnTask, contains a prop named callable equals the task you submit. FuturnTask has its own run method as follows. All exception or throwable throwed in c.call() will be catched and put into a prop named outcome. When calling FuturnTask's get method, outcome will be throwed

提交给ThreadPoolExecutors的任务(Callable或Runnable)将转换为FuturnTask,包含一个名为callable的道具等于您提交的任务。 FuturnTask有自己的run方法如下。 c.call()中抛出的所有异常或抛出都将被捕获并放入一个命名结果。当调用FuturnTask的get方法时,结果将被抛出

FuturnTask.run From Jdk1.8 Source Code

来自Jdk1.8源代码的FuturnTask.run

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

if you want catch the exception :

如果你想抓住异常:

      1. skaffman's answer
      2. overwrite `afterExecute` when you new a ThreadPoolExecutor
        @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
            }
        }

注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:http://www.itdaan.com/blog/2009/11/06/fa0ba01d37b549bd446c3d6a83406600.html



 
© 2014-2018 ITdaan.com 粤ICP备14056181号