英文:
ForkJoinPool: does invokeall() join in the wrong order?
问题
据我所了解,ForkJoinPool使用“后进先出原则(LiFo)”。也许我能找到的最好解释是这个链接。然而,ForkJoinPool.java中的invokeall()
方法似乎以任务提交的顺序(FiFo)加入(是quietlyjoin()
吗?),请参见下面的代码。这样做难道不是更有意义的吗,因为所有处理都是LiFo吗?
这样做是否会减少“补偿线程”?我考虑重新编写我的代码,以LiFo的方式提交任务,而不是使用invokeall()
,并在此基础上加入它们。另请参见:
ForkJoinPool在invokeAll/join期间停顿
编辑:将任务提交到工作程序的外部队列或双端队列会有所区别。我指的是工作程序的双端队列。我认为invokeall()
在这里可能会导致线程停顿。
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
// 在此类的以前版本中,该方法构造了一个任务来运行ForkJoinTask.invokeAll,但现在外部调用多个任务至少同样高效。
ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
try {
for (Callable<T> t : tasks) {
ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
futures.add(f);
externalSubmit(f);
}
for (int i = 0, size = futures.size(); i < size; i++)
((ForkJoinTask<?>) futures.get(i)).quietlyJoin();
return futures;
} catch (Throwable t) {
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(false);
throw t;
}
}
英文:
As far as I understand, a ForkJoinPool uses the 'Last-in-First-Out principle (LiFo)'. Perhaps the best explanation I could find is this link. However, the invokeall()
method in ForkJoinPool.java seems to join (quietlyjoin() ?) the tasks in the order where they were submitted (FiFo), see the code below. Doesn't it make more sense to do it the other way around since all processing is LiFo?
Wouldn't this lead to fewer 'compensation threads' ? I am thinking of rewriting my code to submit tasks, rather than using invokeall()
, and join them on the LiFo basis because of this. See also:
ForkJoinPool stalls during invokeAll/join
ForkJoinPool seems to waste a thread
EDIT: there is a difference whether a task is submitted to the external que or the deque of a worker. I am refering to the deque of the worker. I assume that invokeall() can lead to threadstalling here.
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) {
// In previous versions of this class, this method constructed
// a task to run ForkJoinTask.invokeAll, but now external
// invocation of multiple tasks is at least as efficient.
ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
try {
for (Callable<T> t : tasks) {
ForkJoinTask<T> f = new ForkJoinTask.AdaptedCallable<T>(t);
futures.add(f);
externalSubmit(f);
}
for (int i = 0, size = futures.size(); i < size; i++)
((ForkJoinTask<?>)futures.get(i)).quietlyJoin();
return futures;
} catch (Throwable t) {
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(false);
throw t;
}
}
专注分享java语言的经验与见解,让所有开发者获益!
评论