我们的应用程序具有一些异步运行的代码,但失败了。像这样:
CompletableFuture.runAsync(
() -> { throw new RuntimeException("bad"); },
executorService
);
我们希望默认的异常处理代码能够捕获这些错误,以防万一特定用途忘记处理异常(这是由生产错误引起的)。
这显然很棘手。 Handling exceptions from Java ExecutorService tasks中给出的答案无效。
它依赖于任务为Future<?>
,然后在其上调用get()
,从而导致再次引发异常。但这不是runAsync
代码的情况。
runAsync
创建一个java.util.concurrent.CompletableFuture.AsyncRun
类,该类似乎试图抑制所有异常。尽管本身是Future
,但 not 并不表示自己是isDone()
,并且似乎没有办法摆脱异常。
因此,考虑到以下样板,我们应该如何捕获这些过时的异常?
请注意,我们确实希望某些东西能够捕获runAsync
代码中的所有未处理的异常,而不是我们可以为每个runAsync
调用添加的东西。忘记将处理代码添加到每个代码中太容易了。
public class ExceptionTest {
public static void main(String[] args) throws RuntimeException {
ExecutorService executorService = new ThreadPoolExecutor(
1, 1, 0L,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()
) {
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
// TODO: Magically extract the exception from `r`
}
};
CompletableFuture.runAsync(
() -> { throw new RuntimeException("bad"); },
executorService
);
}
}
答案 0 :(得分:0)
因此,这是一个可怕的骇客,但确实可以解决使用t1.join(); t2.join(); t3.join(); t4.join();
时忘记调用exceptionally
的情况。我希望看到更通用,更简单的解决方案。
它的工作原理是在执行之前拦截runAsync
并在AsyncRun
块上进行修补。
但是,很严重。但这可能会起作用,直到Oracle更改exceptionally
的工作方式。
runAsync