Fork/Join framework в Java

fork/join framework для разбиения задачи на подзадачи и чтобы эти подзадачи выполнялись в отдельных потоках.

Также эти подзадачи могут тоже делиться на подзадачи и опять же чтобы эти подзадачи выполнялись в отдельных потоках.

Повторяться этот процесс деления может пока подзадача не станет необходимо мала.

Есть пул потоков. В один из его потоков ставиться большая задача.

Эта задача и подзадачи в будущем являют собой выполнения метода compile, который нужно переопределить

Example

Переопределяется он всегда похожим образом:

if задача или подзадача уже необходимо мала, возвращаем что-то из метода compile.

else делим задачу или подзадачу на подзадачи.

Деление на подзадачи в else происходит особым рекурсивным образом с помощью методов fork и join.

fork добавляет подзадачу в пул потоков и любой свободный поток может ее подхватить для выполнения. fork вызывает метод compile подзадачи, к которой fork был применен.

join ждет пока эта форкнутая подзадача выполнится.

Search Icon

Внимание джойном останавливается выполнение кода, но поток не блокируется, поток может выполнять другую подзадачу из пула потоков.

join возвращает значение из compile, который fork вызвал.

Ясное дело, compile будет вызываться рекурсивно форком и соответственно джойны будут копиться пока не дойдет до наименьшей подзадачи.

И джойны, понятное дело, в обратном направлении начнут освобождаться.

Помещенные задачи форком в любом потоке в пул потоков могут быть взяты любым свободным потоком для выполнения.

В этом и есть профит, то что задача распараллеливается и любой поток может взять любую подзадачу для выполнения, даже если она была сгенерирована другим потоком.

Пример программы:

import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveTask; public class ForkJoinExample { static volatile int j; public static void main(final String[] arguments) throws InterruptedException, ExecutionException { //узнать количество ядер компьютера //(в каждом ядре эффективно выполнять 1 поток) int nThreads = Runtime.getRuntime().availableProcessors(); System.out.println(nThreads); int[] numbers = new int[1000]; //запишем в массив числа от 1 до 1000 for(int i = 0; i < numbers.length; i++) { numbers[i] = i+1; } //Будем складывать числа от 1 до 1000 //эффективным образом с помощью fork/join // сюда передаем количество // ядер (размер пула потоков) ForkJoinPool forkJoinPool = new ForkJoinPool(nThreads); // invoke запускает задачу на выполнение // то есть вызывает compile. Long result = forkJoinPool.invoke( new Sum(numbers,0,numbers.length)); //пока invoke не вернул значение дальше //в методе мейн ничего не выполняется System.out.println(result); } static class Sum extends RecursiveTask< Long > { int low; int high; int[] array; Sum(int[] array, int low, int high) { this.array = array; this.low = low; this.high = high; } protected Long compute() { //if задача или подзадача уже необходимо мала //возвращаем что-то из метода compile if(high – low <= 10) { long sum = 0; for(int i = low; i < high; ++i) sum += array[i]; return sum; } //else - делим задачу или подзадачу //на подзадачи (в данном случае на 2 половины) else { int mid = low + (high - low) / 2; Sum left = new Sum(array, low, mid); Sum right = new Sum(array, mid, high); // добавляем одну половину задачи (подзадачу) // в пул потоков left.fork(); // добавляем вторую половину задачи (подзадачу) // в пул потоков right.fork(); // ждем когда compile в форке завершиться long leftResult = left.join(); // ждем когда compile в форке завершиться long rightResult = right.join(); return leftResult + rightResult; } } } }

Вывод:

Как можно увидеть, в консоли сумма чисел от 1 до 1000 посчитана верна – 500500.

Что такое сериализация в Java

Узнайте, как работает сериализация в Java: сохраняйте объекты в файлы с ObjectOutputStream и восстанавливайте их через ObjectInputStream. Пример кода и важность интерфейса Serializable.
Time to read: 10

Transient в Java

Ключевое слово transient в Java: как исключить поля из сериализации. Практическое руководство по работе с несериализуемыми данными.
Time to read: 8

Контроль совместимости классов с помощью SerialVersionUID

Используйте SerialVersionUID в Java для контроля версий классов при сериализации. Решение проблем совместимости при изменении структуры класса.
Time to read: 9