一、介紹
1、Fork/Join框架是Java7提供了的一個用於並行執行任務的框架, 是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。
Fork:把一個大任務切分爲若干子任務並行的執行。
Join:合併這些子任務的執行結果,最後得到這個大任務的結果。
上圖中,上部的Task依賴於下部的Task執行,只有當各個子任務執行完成後,才能得到Task0的返回結果。
2、原理
分割任務。需要有一個fork類來將主任務分割成子任務,存在嵌套分隔的情況。
執行任務併合並結果。分割的子任務分別放在各自的雙端隊列中,之後啓動幾個線程分別從其所有的雙端隊列中獲取任務執行。子任務執行完的結果都統一放在一個結果隊列中,啓動一個線程從此隊列中獲取併合並數據。
Fork/Join使用兩個類來完成以上兩件事情:
- ForkJoinTask:使用ForkJoin框架,必須首先創建一個ForkJoin任務。它提供在任務中執行fork()和join()操作,通常情況下我們不需要直接繼承ForkJoinTask類,而只需要繼承它的子類,Fork/Join框架提供了以下兩個子類:
- RecursiveAction:用於沒有返回結果的任務。
- RecursiveTask :用於有返回結果的任務。
- ForkJoinPool :ForkJoinTask需要通過ForkJoinPool來執行,任務分割出的子任務會添加到當前工作線程所維護的雙端隊列中,進入隊列的頭部。當一個工作線程的隊列裏暫時沒有任務時,它會隨機從其他工作線程的隊列的尾部獲取一個任務。
二、例子
通過一個例子,簡單介紹fork/join框架的使用,計算任務是:計算1 + 2 + … + 100
1、首先是繼承類,由於我們需要子任務返回結果,因此選擇帶有返回結果的RecursiveTask
。
2、繼承RecursiveTask
類後,需要實現其父類的抽象方法compute()
。
3、任務分隔, 設定閾值爲10,如果超過該閾值,則進行分隔。
public class CountTask extends RecursiveTask<Integer> {
private static final int THRESHOLD = 10; // 閾值
private int start;
private int end;
public CountTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
boolean isNeedSplit = (end - start) > THRESHOLD;
int sum = 0;
if (!isNeedSplit) {
for (int i = start; i <= end; ++i) {
sum += i;
}
return sum;
}
// 分隔任務
int mid = (start + end) >> 1;
CountTask lowTask = new CountTask(start, mid);
CountTask highTask = new CountTask(mid + 1, end);
// 子任務執行
lowTask.fork();
highTask.fork();
// 獲取子任務計算結果
return lowTask.join() + highTask.join();
}
public static void main(String[] args) throws Exception {
ForkJoinPool forkJoinPool = new ForkJoinPool();
// 創建新任務
CountTask task = new CountTask(1, 100);
// 提交任務
Future<Integer> ret = forkJoinPool.submit(task);
// 輸出結果
System.out.println(ret.get());
}
}