背景:ForkJoinPool的優勢在于,可以充分利用多cpu,多核cpu的優勢,把一個任務拆分成多個“小任務”,把多個“小任務”放到多個處理器核心上并行執行;當多個“小任務”執行完成之後,再将這些執行結果合并起來即可。這種思想值得學習。
主要參考《瘋狂java講義》
回到頂部
使用
Java7 提供了ForkJoinPool來支援将一個任務拆分成多個“小任務”并行計算,再把多個“小任務”的結果合并成總的計算結果。
ForkJoinPool是ExecutorService的實作類,是以是一種特殊的線程池。
使用方法:建立了ForkJoinPool執行個體之後,就可以調用ForkJoinPool的submit(ForkJoinTask<T> task) 或invoke(ForkJoinTask<T> task)方法來執行指定任務了。
其中ForkJoinTask代表一個可以并行、合并的任務。ForkJoinTask是一個抽象類,它還有兩個抽象子類:RecusiveAction和RecusiveTask。其中RecusiveTask代表有傳回值的任務,而RecusiveAction代表沒有傳回值的任務。
下面的UML類圖顯示了ForkJoinPool、ForkJoinTask之間的關系:
舉例
以還行沒有傳回值的“大任務”(簡單低列印1~300的數值)為例,程式将一個“大任務”拆分成多個“小任務”,并将任務交給ForkJoinPool來執行
/**
* Project Name:Spring0725
* File Name:ForkJoinPoolAction.java
* Package Name:work1201.basic
* Date:2017年12月4日下午2:26:55
* Copyright (c) 2017, 深圳金融電子結算中心 All Rights Reserved.
*
*/
package work1201.basic;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.TimeUnit;
/**
* ClassName:ForkJoinPoolAction <br/>
* Function: 使用ForkJoinPool完成一個任務的分段執行
* 簡單的列印0-300的數值。用多線程實作并行執行
* Date: 2017年12月4日 下午2:26:55 <br/>
* @author prd-lxw
* @version 1.0
* @since JDK 1.7
* @see
*/
public class ForkJoinPoolAction {
public static void main(String[] args) throws Exception{
PrintTask task = new PrintTask(0, 300);
//建立執行個體,并執行分割任務
ForkJoinPool pool = new ForkJoinPool();
pool.submit(task);
//線程阻塞,等待所有任務完成
pool.awaitTermination(2, TimeUnit.SECONDS);
pool.shutdown();
}
}
/**
* ClassName: PrintTask <br/>
* Function: 繼承RecursiveAction來實作“可分解”的任務。
* date: 2017年12月4日 下午5:17:41 <br/>
*
* @author prd-lxw
* @version 1.0
* @since JDK 1.7
*/
class PrintTask extends RecursiveAction{
private static final int THRESHOLD = 50; //最多隻能列印50個數
private int start;
private int end;
public PrintTask(int start, int end) {
super();
this.start = start;
this.end = end;
}
@Override
protected void compute() {
if(end - start < THRESHOLD){
for(int i=start;i<end;i++){
System.out.println(Thread.currentThread().getName()+"的i值:"+i);
}
}else {
int middle =(start+end)/2;
PrintTask left = new PrintTask(start, middle);
PrintTask right = new PrintTask(middle, end);
//并行執行兩個“小任務”
left.fork();
right.fork();
}
}
}