为什么并行性ForkJoinPool双倍我的例外? [英] Why a parallelism ForkJoinPool double my exception?

查看:189
本文介绍了为什么并行性ForkJoinPool双倍我的例外?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有如下代码:

 未来<对象> executeBy(ExecutorService executor){
return executor.submit(() - > {
throw new IllegalStateException();
});
}

使用时没有问题ForkJoinPool#commonPool ,但是当我使用并行性 ForkJoinPool 时,它将使 IllegalStateException 加倍。例如:

  executeBy(new ForkJoinPool(1))。get(); 
// ^ --- double of IllegalStateException

Q1 :为什么并行性 ForkJoinPool 双重异常发生在可调用



Q2 :如何避免这种奇怪的行为?

解决方案

如果在工作线程中抛出异常并将原始异常设置为原因,则Fork / Join池通常会尝试在调用者线程中重新创建异常。这就是你所认为的倍增。当您仔细查看堆栈跟踪时,您会注意到这两个异常之间的区别。



公共池在这方面没有什么不同。但是公共池允许调用者线程在等待最终结果时参与工作。所以当你把你的代码改成

  static Future< Object> executeBy(ExecutorService executor){
return executor.submit(() - > {
throw new IllegalStateException(Thread.currentThread()。toString());
});
}

你会注意到,通常发生呼叫线程在调用 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;
}
};
});
}


assuming I have the code like as below:

Future<Object> executeBy(ExecutorService executor) {
    return executor.submit(() -> {
        throw new IllegalStateException();
    });
}

there is no problem when using ForkJoinPool#commonPool, but when I using a parallelism ForkJoinPool it will double the IllegalStateException. for example:

executeBy(new ForkJoinPool(1)).get(); 
//                              ^--- double the IllegalStateException

Q1: why the parallelism ForkJoinPool double the Exception occurs in the Callable?

Q2: how to avoiding this strange behavior?

解决方案

The Fork/Join pool generally attempts to recreate the exception within the caller’s thread if the exception has been thrown in a worker thread and sets the original exception as its cause. This is what you perceived as "doubling". When you look closer at the stack traces, you will notice the difference between these two exceptions.

The common pool is not different in that regard. But the common pool allows the caller thread to participate in the work when waiting for the final result. So when you change you code to

static Future<Object> executeBy(ExecutorService executor) {
    return executor.submit(() -> {
        throw new IllegalStateException(Thread.currentThread().toString());
    });
}

you will notice that it often happens that the caller thread is faster in calling get() and do work-stealing within that method than a worker thread can pick up the task. In other words, your supplier has been executed within the main/caller thread and in this case, the exception will not be recreated.

This feature can easily disabled by throwing an exception type which has no matching public constructor the F/J could use, like with this neat inner class:

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

这篇关于为什么并行性ForkJoinPool双倍我的例外?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆