聲明:原創(chuàng)文章,轉(zhuǎn)載請注明出處。http://www.reibang.com/u/e02df63eaa87
一、介紹
1节视、Fork/Join框架是Java7提供了的一個用于并行執(zhí)行任務的框架, 是一個把大任務分割成若干個小任務假栓,最終匯總每個小任務結(jié)果后得到大任務結(jié)果的框架寻行。
Fork:把一個大任務切分為若干子任務并行的執(zhí)行。
Join:合并這些子任務的執(zhí)行結(jié)果但指,最后得到這個大任務的結(jié)果寡痰。
上圖中,上部的Task依賴于下部的Task執(zhí)行棋凳,只有當各個子任務執(zhí)行完成后拦坠,才能得到Task0的返回結(jié)果。
2剩岳、原理
分割任務贞滨。需要有一個fork類來將主任務分割成子任務,存在嵌套分隔的情況拍棕。
執(zhí)行任務并合并結(jié)果晓铆。分割的子任務分別放在各自的雙端隊列中,之后啟動幾個線程分別從其所有的雙端隊列中獲取任務執(zhí)行绰播。子任務執(zhí)行完的結(jié)果都統(tǒng)一放在一個結(jié)果隊列中骄噪,啟動一個線程從此隊列中獲取并合并數(shù)據(jù)。
Fork/Join使用兩個類來完成以上兩件事情:
- ForkJoinTask:使用ForkJoin框架蠢箩,必須首先創(chuàng)建一個ForkJoin任務链蕊。它提供在任務中執(zhí)行fork()和join()操作,通常情況下我們不需要直接繼承ForkJoinTask類谬泌,而只需要繼承它的子類滔韵,F(xiàn)ork/Join框架提供了以下兩個子類:
- RecursiveAction:用于沒有返回結(jié)果的任務。
- RecursiveTask :用于有返回結(jié)果的任務掌实。
- ForkJoinPool :ForkJoinTask需要通過ForkJoinPool來執(zhí)行陪蜻,任務分割出的子任務會添加到當前工作線程所維護的雙端隊列中,進入隊列的頭部贱鼻。當一個工作線程的隊列里暫時沒有任務時宴卖,它會隨機從其他工作線程的隊列的尾部獲取一個任務滋将。
二、例子
通過一個例子症昏,簡單介紹fork/join框架的使用耕渴,計算任務是:計算1 + 2 + ... + 100
1、首先是繼承類齿兔,由于我們需要子任務返回結(jié)果,因此選擇帶有返回結(jié)果的RecursiveTask
础米。
2分苇、繼承RecursiveTask
類后,需要實現(xiàn)其父類的抽象方法compute()
屁桑。
3医寿、任務分隔, 設(shè)定閾值為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);
// 子任務執(zhí)行
lowTask.fork();
highTask.fork();
// 獲取子任務計算結(jié)果
return lowTask.join() + highTask.join();
}
public static void main(String[] args) throws Exception {
ForkJoinPool forkJoinPool = new ForkJoinPool();
// 創(chuàng)建新任務
CountTask task = new CountTask(1, 100);
// 提交任務
Future<Integer> ret = forkJoinPool.submit(task);
// 輸出結(jié)果
System.out.println(ret.get());
}
}