Fork/Join框架是Java7提供了的一個用於並行執行任務的框架, 是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。
Fork就是把一個大任務切分爲若干子任務並行的執行。類似MapReduce裏面的Map。
Join就是合併這些子任務的執行結果,最後得到這個大任務的結果。類似MapReduce裏面的Reduce。
舉例說明,統計1~100的和,並行運行, 每個線程計算20個數的,如果當前線程統計的數量多於20,就切分爲兩個線程運行,切分點爲中間數,至少分配的每一個線程的統計數小於或等於20,這個分裂任務的過程就叫做Fork。最後各個線程向上彙報彙總結果,這個匯聚結果的過程就叫做Join。
流程圖如下:
代碼如下:
import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; import java.util.concurrent.RecursiveTask; import java.util.concurrent.atomic.AtomicInteger; class Calculator extends RecursiveTask<Integer> { /** * */ private static final long serialVersionUID = 1L; /** * 線程計數器 */ public static AtomicInteger tcounter = new AtomicInteger(0); /** * 計算閥值 */ private static final int THRESHOLD = 20; /** * 開始值 */ private int start; /** * 結束值 */ private int end; public Calculator(int start, int end) { this.start = start; this.end = end; } @Override protected Integer compute() { tcounter.incrementAndGet(); System.out.println("start:" + start + ", end:" + end); int sum = 0; if((end - start) <= THRESHOLD) { /** * 小於等於閥值,直接計算 */ for(int i = start; i<= end; i++) { sum += i; } } else { /** * 大於閥值,任務分解, 並匯聚結果 */ int middle = (start + end) / 2; Calculator left = new Calculator(start, middle); Calculator right = new Calculator(middle + 1, end); left.fork(); right.fork(); sum = left.join() + right.join(); } return sum; } } public class TestForkJoinPool { public static void main(String[] args) throws InterruptedException, ExecutionException { ForkJoinPool forkJoinPool = new ForkJoinPool(); Future<Integer> result = forkJoinPool.submit(new Calculator(1, 100)); System.out.println("結果: " + result.get() + ", " + Calculator.tcounter + "個線程參與了運算"); } }
執行結果
start:1, end:100 start:1, end:50 start:51, end:100 start:1, end:25 start:1, end:13 start:26, end:50 start:14, end:25 start:51, end:75 start:26, end:38 start:39, end:50 start:51, end:63 start:64, end:75 start:76, end:100 start:76, end:88 start:89, end:100 結果: 5050, 15個線程參與了運算
聊聊核心類,
ForkJoinPool:負責建立一個ForkJoin運行環境
ForkJoinTask: 表示實際運行的任務,一般使用它的兩個子類,一個是RecursiveAction(任務不帶返回值時使用),另一個是RecursiveTask(任務帶返回值時使用)。按照情況選擇任意一個, 使用時需要繼承該子類,然後實現抽象方法compute【任務的邏輯就在compute方法裏編寫】。
ForkJoinTask.fork方法表示分裂任務, ForkJoinTask.join表示匯聚分裂任務的compute方法的執行結果。