ExecutorService
ExecutorService
called ForkJoinPool
ForkJoinPool
. This implementation is designed specifically to simplify the parallelization of recursive tasks and solves the problem with the fact that while the sub-task is being executed, the thread that generated it cannot be used. ForkJoinPool
, which will be discussed below, you can perform a significantly larger number of tasks in a small number of threads. This is achieved by the so-called work-stealing , when the sleeping task actually does not sleep, but performs other tasks. This class has many interesting methods, but we will dwell only on two: fork()
, which performs an asynchronous start of the task and join()
, which waits until the task is completed and returns the result of its execution. A more detailed description of all methods can be found in the official documentation .RecursiveAction
RecursiveAction
in case you don’t need to calculate any value, you just need to perform some action, and RecursiveTask
RecursiveTask
, when you still need to return something. As you can see, these two classes are similar to the existing ones. Runnable
Runnable
and Callable
Callable
. public interface Node { Collection<Node> getChildren(); long getValue(); }
fork()
and join
methods: public class ValueSumCounter extends RecursiveTask<Long>{ private final Node node; public ValueSumCounter(Node node) { this.node = node; } @Override protected Long compute() { long sum = node.getValue(); List<ValueSumCounter> subTasks = new LinkedList<>(); for(Node child : node.getChildren()) { ValueSumCounter task = new ValueSumCounter(child); task.fork(); // subTasks.add(task); } for(ValueSumCounter task : subTasks) { sum += task.join(); // } return sum; } }
ForkJoinPool
: public static void main(String[] args) { Node root = getRootNode(); new ForkJoinPool().invoke(new ValueSumCounter(root)); }
Future<T>
. Moreover, as I wrote earlier, it is not necessary to select a dedicated real stream to perform the fork task. On the contrary, already existing threads that are currently in join-e are actively used. This, obviously, gives a significant increase in performance. I did not conduct a benchmark, because I am sure that the engineers at Oracle have already done this for me.Source: https://habr.com/ru/post/128985/
All Articles