Насколько я понимаю, ForkJoinPool использует принцип «последним пришел — первым ушел» (LiFo). Возможно, лучшее объяснение, которое я смог найти, это эта ссылка. Однако метод invokeall()
в ForkJoinPool.java, по-видимому, объединяет (quietlyjoin()?) задачи в том порядке, в котором они были отправлены (FiFo), см. код ниже. Не лучше ли сделать наоборот, ведь вся обработка LiFo?
Не приведет ли это к меньшему количеству «компенсационных потоков»? Я думаю переписать свой код для отправки задач, а не использовать invokeall()
, и из-за этого присоединиться к ним на основе LiFo. Смотрите также:
ForkJoinPool останавливается во время invokeAll/join
ForkJoinPool, похоже, теряет поток
РЕДАКТИРОВАТЬ: существует разница в том, отправляется ли задача во внешнюю очередь или в очередь исполнителя. Я имею в виду деку рабочего. Я предполагаю, что invokeall() может привести к остановке потока здесь.
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;
}
}
ForkJoinTask
s и подзадач, отправленных черезForkJoinTask.invokeAll()
(потому что именно здесь происходит рекурсивное разделение (также известное как fork/join), приводящее к поведению LIFO). При использованииForkJoinPool.invokeAll()
между задачами нет зависимостей, поэтому объединение по порядку не имеет большого значения по сравнению с объединением их в обратном порядке. - person Thomas Kläger   schedule 06.04.2020ForkJoinPool
s, поэтому он остановится до тех пор, пока не будут выполнены все 5 задач, независимо от того, в каком порядке они выполняются. 5 задач выполняются параллельно в рабочих потоках изForkJoinPool
, порождая по 3 подзадачи в каждой. При попытке присоединиться к подзадачам рабочие потоки не останавливаются, а выполняют другую работу из своих рабочих очередей (каждая из которых содержит 3 подзадачи). - person Thomas Kläger   schedule 06.04.2020invokeAll()
не делаетThread.join()
(что остановит). Вместо этого он решает: если текущий поток является внешним потоком (например, основным потоком), он ожидает завершения. Если запущенный поток являетсяForkJoinWorkerThread
, он попытается выполнить другую работу (либо из своей собственной рабочей очереди, либо путем кражи работы из других очередей). - person Thomas Kläger   schedule 06.04.2020