聲明:原創(chuàng)文章,轉(zhuǎn)載請注明出處。http://www.lxweimin.com/u/e02df63eaa87
一、介紹
1、Fork/Join框架是Java7提供了的一個用于并行執(zhí)行任務(wù)的框架, 是一個把大任務(wù)分割成若干個小任務(wù),最終匯總每個小任務(wù)結(jié)果后得到大任務(wù)結(jié)果的框架。
Fork:把一個大任務(wù)切分為若干子任務(wù)并行的執(zhí)行。
Join:合并這些子任務(wù)的執(zhí)行結(jié)果,最后得到這個大任務(wù)的結(jié)果。
上圖中,上部的Task依賴于下部的Task執(zhí)行,只有當(dāng)各個子任務(wù)執(zhí)行完成后,才能得到Task0的返回結(jié)果。
2、原理
分割任務(wù)。需要有一個fork類來將主任務(wù)分割成子任務(wù),存在嵌套分隔的情況。
執(zhí)行任務(wù)并合并結(jié)果。分割的子任務(wù)分別放在各自的雙端隊列中,之后啟動幾個線程分別從其所有的雙端隊列中獲取任務(wù)執(zhí)行。子任務(wù)執(zhí)行完的結(jié)果都統(tǒng)一放在一個結(jié)果隊列中,啟動一個線程從此隊列中獲取并合并數(shù)據(jù)。
Fork/Join使用兩個類來完成以上兩件事情:
- ForkJoinTask:使用ForkJoin框架,必須首先創(chuàng)建一個ForkJoin任務(wù)。它提供在任務(wù)中執(zhí)行fork()和join()操作,通常情況下我們不需要直接繼承ForkJoinTask類,而只需要繼承它的子類,F(xiàn)ork/Join框架提供了以下兩個子類:
- RecursiveAction:用于沒有返回結(jié)果的任務(wù)。
- RecursiveTask :用于有返回結(jié)果的任務(wù)。
- ForkJoinPool :ForkJoinTask需要通過ForkJoinPool來執(zhí)行,任務(wù)分割出的子任務(wù)會添加到當(dāng)前工作線程所維護(hù)的雙端隊列中,進(jìn)入隊列的頭部。當(dāng)一個工作線程的隊列里暫時沒有任務(wù)時,它會隨機從其他工作線程的隊列的尾部獲取一個任務(wù)。
二、例子
通過一個例子,簡單介紹fork/join框架的使用,計算任務(wù)是:計算1 + 2 + ... + 100
1、首先是繼承類,由于我們需要子任務(wù)返回結(jié)果,因此選擇帶有返回結(jié)果的RecursiveTask
。
2、繼承RecursiveTask
類后,需要實現(xiàn)其父類的抽象方法compute()
。
3、任務(wù)分隔, 設(shè)定閾值為10,如果超過該閾值,則進(jìn)行分隔。
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;
}
// 分隔任務(wù)
int mid = (start + end) >> 1;
CountTask lowTask = new CountTask(start, mid);
CountTask highTask = new CountTask(mid + 1, end);
// 子任務(wù)執(zhí)行
lowTask.fork();
highTask.fork();
// 獲取子任務(wù)計算結(jié)果
return lowTask.join() + highTask.join();
}
public static void main(String[] args) throws Exception {
ForkJoinPool forkJoinPool = new ForkJoinPool();
// 創(chuàng)建新任務(wù)
CountTask task = new CountTask(1, 100);
// 提交任務(wù)
Future<Integer> ret = forkJoinPool.submit(task);
// 輸出結(jié)果
System.out.println(ret.get());
}
}