У меня есть ситуация, для которой у меня возникают проблемы, чтобы найти чистое решение. Я попытаюсь объяснить как можно подробнее.
У меня есть древовидная структура:
NODE A
NODE A.1
NODE A.2
NODE A.2.a
NODE A.2.b
NODE A.3
NODE A.3.a
NODE A.3.b
NODE A.3.c
NODE B
NODE B.1
NODE B.2
Мне нужно обработать корень node:
public void process(final Node node) { ... }
Процесс node включает в себя две вещи:
- some database queries
- the process of all children of these nodes
Другими словами, после обработки NODE.2.a
и NODE.2.b
обрабатывается NODE.2
. Я обрабатываю узлы рекурсивным образом, ничего впечатляющего.
До сих пор так хорошо. Теперь я хочу объявить глобальную службу исполнителей с фиксированным количеством потоков. Я хочу обрабатывать дочерние узлы node параллельно. Таким образом, NODE.2.a
и NODE.2.b
могут обрабатываться каждый в своих потоках. Код будет выглядеть примерно так:
// global executor service, shared between all process(Node) calls
final ExecutorService service = Executors.newFixedThreadPool(4);
public void process(final Node node) {
// database queries
...
// wait for children to be processed
final CountDownLatch latch = new CountDownLatch(node.children().size());
for (final Node child : node.children()) {
service.execute(() -> {
process(child);
latch.countDown();
});
}
latch.await();
}
Проблема здесь: при достижении определенной глубины все потоки останавливаются в latch.await()
. Мы достигли ситуации голодного голода.
Это можно легко решить, сделав службу исполнителя неограниченной, но мне не нравится этот параметр. Я хочу контролировать количество потоков active
. В моем случае количество потоков active
будет равно числу ядер. Наличие более active
потоков приведет к свопам из одного потока в другой, и я хотел бы избежать этого.
Как это можно решить?