hol*_*ava 4 java exception fork-join java-8
假设我有如下代码:
Future<Object> executeBy(ExecutorService executor) {
return executor.submit(() -> {
throw new IllegalStateException();
});
}
Run Code Online (Sandbox Code Playgroud)
使用ForkJoinPool#commonPool时没有问题,但是当我使用并行性时ForkJoinPool它会加倍IllegalStateException.例如:
executeBy(new ForkJoinPool(1)).get();
// ^--- double the IllegalStateException
Run Code Online (Sandbox Code Playgroud)
Q1:为什么并行ForkJoinPool一倍Exception发生在Callable?
Q2:如何避免这种奇怪的行为?
Hol*_*ger 11
如果在工作线程中抛出异常并将原始异常设置为其原因,则Fork/Join池通常会尝试在调用者的线程内重新创建异常.这就是你所认为的"倍增".当您仔细观察堆栈跟踪时,您会注意到这两个异常之间的区别.
在这方面,共同池没有什么不同.但是公共池允许调用者线程在等待最终结果时参与工作.所以,当你将代码更改为
static Future<Object> executeBy(ExecutorService executor) {
return executor.submit(() -> {
throw new IllegalStateException(Thread.currentThread().toString());
});
}
Run Code Online (Sandbox Code Playgroud)
你会注意到,通常会发生调用者线程在调用中更快get()并且在该方法中进行工作窃取而不是工作线程可以接收任务.换句话说,您的供应商已在主/调用者线程中执行,在这种情况下,将不会重新创建异常.
通过抛出一个没有F/J可以使用的匹配公共构造函数的异常类型,可以轻松禁用此功能,就像这个整洁的内部类一样:
static Future<Object> executeBy(ExecutorService executor) {
return executor.submit(() -> {
throw new IllegalStateException() {
@Override
public String toString() {
String s = getClass().getSuperclass().getName();
String message = getLocalizedMessage();
return message!=null? s+": "+message: s;
}
};
});
}
Run Code Online (Sandbox Code Playgroud)
在ForkJoinPool创建ForkJoinTask实例来执行你的意见.
ForkJoinTask尝试在发生异常时提供准确的堆栈跟踪.它的javadoc说
Rethrown异常的行为方式与常规异常相同,但在可能的情况下,包含
ex.printStackTrace()启动计算的线程以及实际遇到异常的线程的堆栈跟踪(如示例所示 ).最低限度只有后者.
Run Code Online (Sandbox Code Playgroud)/** * Returns a rethrowable exception for the given task, if * available. To provide accurate stack traces, if the exception * was not thrown by the current thread, we try to create a new * exception of the same type as the one thrown, but with the * recorded exception as its cause. If there is no such * constructor, we instead try to use a no-arg constructor, * followed by initCause, to the same effect. If none of these * apply, or any fail due to other exceptions, we return the * recorded exception, which is still correct, although it may * contain a misleading stack trace. * * @return the exception, or null if none */ private Throwable getThrowableException() {
换句话说,它需要IllegalStateException你的代码抛出,找到一个IllegalStateException接收a 的构造函数Throwable,调用该构造函数并将原始IllegalStateException作为其参数,并返回结果(然后在a中重新抛出ExecutionException).
您的堆栈跟踪现在还包含该get调用的堆栈跟踪.
随着ForkJoinPool作为你的ExecutorService,我不相信你可以避开它,它是依赖于如果异常没有被当前线程抛出在抛出的异常类型和可用的构造函数.
| 归档时间: |
|
| 查看次数: |
1199 次 |
| 最近记录: |