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]