場景:當任務很多,成千上萬個,或者單個任務很大,執行起來很耗時間,這時,就可以把任務進行拆分,拆分成多個小任務去執行,然後小任務執行完畢後再把每個小任務執行的結果合併起來,這樣就可以節省時間。
ForkJoinPool實現了ExecutorService接口,所以它也是一種線程池,做的工作就是,把一個任務拆分成若干個小任務執行,然後再把小任務執行的結果彙總。
下面是一個小例子:
//初始化一個ForkJoinPool
static ForkJoinPool pool = new ForkJoinPool(3,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null,
true);
//一個集合,模擬網站
static ArrayList<String> list = new ArrayList<>();
//集合中的數據
static void addList() {
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
list.add("www.baidu.com");
list.add("www.blog.csdn.net");
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
addList();
//提交任務
ForkJoinTask<String> task = pool.submit(new Work(list, 0, list.size()));
System.out.println(task.get());
}
//模擬請求
public static String doRequest(String url, int index) {
return index + "--》請求測試:" + url + "\n";
}
//需要繼承RecursiveTask,來實現自己的拆分邏輯
static class Work extends RecursiveTask<String> {
List<String> list;
int start;
int end;
public Work(List<String> list, int start, int end) {
this.list = list;
this.start = start;
this.end = end;
}
@Override
protected String compute() {
int count = end - start;
String result = "";
//當任務小於10個時直接執行,否則就拆分
if (count <= 10) {
for (int i = 0; i<list.size(); i++) {
result += doRequest(list.get(i), i);
}
return result;
} else {
//獲取任務數量索引的中間值
int x = (start + end) / 2;
//拆分任務
Work work1 = new Work(list, start, x);
work1.fork();
//拆分任務
Work work2 = new Work(list, x, end);
work2.fork();
//獲取任務執行結果
result += work1.join();
result += work2.join();
return result;
}
}
}
執行邏輯:
第一步:
第二步:
第三步:
每一個線程有任務後,都會去拆分任務,當拆分的小任務滿足執行條件後,就會去執行,然後按照層級,從拆分後最小的層級執行完任務,一層層向上回收任務結果,最後到ForkJoinTask中,然後就可以獲取到每一個小任務執行的結果。