Java Fork/Joinフレームワークの例
fork/joinフレームワークは、Java 7以降で使用でき、並列プログラムの作成を容易にします。
RecursiveTask`または
RecursiveAction`のいずれかを拡張することによって、fork/joinフレームワークを実装できます
1.フォーク/結合 – RecursiveTask
範囲からすべての数値を合計するフォーク結合の例。
ForkJoinAdd.java
package com.mkyong.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<Long> {
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<Long> task = new ForkJoinAdd(numbers);
return new ForkJoinPool().invoke(task);
}
}
それを実行します。 1から100万までのすべての数値を合計します。
Main.java
package com.mkyong.concurrency.forkjoin;
public class Main {
public static void main(String[]args) {
System.out.println(ForkJoinAdd.startForkJoinSum(1__000__000));
}
}
出力
500000500000
2.フォーク/結合 – RecursiveAction
再帰的ループを使用してフィボナッチ数を見つけるフォーク結合の例。
-
注意** このメソッドは、Fork/Joinデモ専用です。再帰ループは遅いです。フィボナッチ数をより速く見つけるには、//java/java-fibonacci-examples/[Java Fibonacciの例]を参照してください。
ForkJoinFibonacci.java
package com.mkyong.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.mkyong.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
-
RecursiveTaskとRecursiveActionの違い?** +どちらも同じですが、 `RecursiveTask`は値を返し、RecursiveActionは何も返しません。
ソースコードをダウンロードする
$ git clone
https://github.com/mkyong/java-concurrency.git
参考文献
-
https://docs.oracle.com/javase/tutorial/essential/concurrency/forkjoin.html
[Oracle-
フォーク/参加]
-
-
http://gee.cs.oswego.edu/dl/papers/fj.pdf
[Doug Lea – Javaフォーク/結合
フレームワーク]。
https://en.wikipedia.org/wiki/Fibonacci__number
[ウィキペディア – フィボナッチ
数]。リンク://java/java-fibonacci-examples/[Javaフィボナッチの例]
JavaDoc]。
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/RecursiveAction.html
[RecursiveAction
JavaDoc]