Примеры Java Fork / Join Framework
What is Fork/Join?
Прочтите этоJava Fork/Join paper by Doug Lea
Фреймворк fork / join доступен с Java 7, чтобы упростить написание параллельных программ. Мы можем реализовать структуру fork / join, расширивRecursiveTask илиRecursiveAction
1. Fork/Join – RecursiveTask
Пример объединения вилок для суммирования всех чисел из диапазона.
ForkJoinAdd.java
package com.example.concurrency.forkjoin; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; import java.util.stream.LongStream; public class ForkJoinAdd extends RecursiveTask{ private final long[] numbers; private final int start; private final int end; public static final long threshold = 10_000; public ForkJoinAdd(long[] numbers) { this(numbers, 0, numbers.length); } private ForkJoinAdd(long[] numbers, int start, int end) { this.numbers = numbers; this.start = start; this.end = end; } @Override protected Long compute() { int length = end - start; if (length <= threshold) { return add(); } ForkJoinAdd firstTask = new ForkJoinAdd(numbers, start, start + length / 2); firstTask.fork(); //start asynchronously ForkJoinAdd secondTask = new ForkJoinAdd(numbers, start + length / 2, end); Long secondTaskResult = secondTask.compute(); Long firstTaskResult = firstTask.join(); return firstTaskResult + secondTaskResult; } private long add() { long result = 0; for (int i = start; i < end; i++) { result += numbers[i]; } return result; } public static long startForkJoinSum(long n) { long[] numbers = LongStream.rangeClosed(1, n).toArray(); ForkJoinTask task = new ForkJoinAdd(numbers); return new ForkJoinPool().invoke(task); } }
Запустить его. Суммируйте все числа от 1 до 1 миллиона.
Main.java
package com.example.concurrency.forkjoin;
public class Main {
public static void main(String[] args) {
System.out.println(ForkJoinAdd.startForkJoinSum(1_000_000));
}
}
Выход
500000500000
2. Fork/Join – RecursiveAction
Пример соединения с вилкой, чтобы найти число Фибоначчи с помощью рекурсивного цикла.
Note
Этот метод используется только для демонстрации Fork / Join, рекурсивный цикл медленный. Попробуйте этотJava Fibonacci examples, чтобы быстрее найти число Фибоначчи.
ForkJoinFibonacci.java
package com.example.concurrency.forkjoin;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveAction;
public class ForkJoinFibonacci extends RecursiveAction {
private static final long threshold = 10;
private volatile long number;
public ForkJoinFibonacci(long number) {
this.number = number;
}
public long getNumber() {
return number;
}
@Override
protected void compute() {
long n = number;
if (n <= threshold) {
number = fib(n);
} else {
ForkJoinFibonacci f1 = new ForkJoinFibonacci(n - 1);
ForkJoinFibonacci f2 = new ForkJoinFibonacci(n - 2);
ForkJoinTask.invokeAll(f1, f2);
number = f1.number + f2.number;
}
}
private static long fib(long n) {
if (n <= 1) return n;
else return fib(n - 1) + fib(n - 2);
}
}
Запустите его, найдите 50-е число Фибоначчи.
Main.java
package com.example.concurrency.forkjoin;
import java.util.concurrent.ForkJoinPool;
public class Main {
public static void main(String[] args) {
ForkJoinFibonacci task = new ForkJoinFibonacci(50);
new ForkJoinPool().invoke(task);
System.out.println(task.getNumber());
}
}
Выход
12586269025
Difference between RecursiveTask and RecursiveAction?
Оба они одинаковы, простоRecursiveTask возвращает значение, а RecursiveAction ничего не возвращает, void.
Скачать исходный код
$ git clone https://github.com/example/java-concurrency.git