一、ForkJoin說明
ForkJoin是jdk1.7增加的併發工具類,可以解決分而治之的問題,就是把一個任務分爲若干小任務,併發的去處理,最後再把處理結果合併起來,從而達到提高速度的目的。使用時要保證每個小任務互不干擾、相互獨立且結構和主任務相同,用遞歸的方法解決這些小任務,最終合併到一起
二、ForkJoin使用
1.首先創建ForkJoinPool,ForkJoinPool可以理解爲一個線程池,裏面維護的線程數一般爲cpu核數,不斷的執行拆分的任務,並且還會工作竊取,就是自己的活要是幹完了空閒了,會獲取其他線程的task,從而達到空閒率,提高效率。
ForkJoinPool pool=new ForkJoinPool()
**2.創建ForkJoin任務,**去交給ForkJoinPool執行,一般我們會繼承ForkjoinTask的子類RecursiveAction或者RecursiveTask
(1)RecursiveAction沒有返回值的任務
(2)RecursiveTask用於有返回值的任務
然後要實現裏面的compute方法,compute方法裏面先要判斷是否滿足我們拆分的最小任務條件,如果滿足就執行處理方法並把結果交給上一級的任務(就是拆分出來現在小任務的那個任務);如果不滿足調用fork或者invokeAll(遞歸)再去拆分;最後通過join(阻塞方法)彙總
3.執行ForkJoinPool的submit 或 invoke第一次拆分提交
(1)submit是異步執行
(2)invoke是同步執行,必須等到任務完成,纔會執行下面代碼
下面是個具體實例計算1~40000的值
public class ForkJoinTest extends RecursiveTask<Integer> {
private int[] arrys;//存放相加數據的數組
private int THRESHOLD=400;//定義閾值,拆成每個數組400個元素
private int startIndex;
private int endIndex;
public ForkJoinTest(int[] arrys,int startIndex,int endIndex){
this.arrys=arrys;
this.startIndex=startIndex;
this.endIndex=endIndex;
}
@Override
protected Integer compute() {
if(endIndex-startIndex<=THRESHOLD){//判斷拆分數組長度是否在閾值內
int count=0;
for(int i=startIndex;i<=endIndex;i++){
count+=arrys[i];
}
return count;//將結果交給上一級task
}else{
int mid=(startIndex+endIndex)/2;//找中值繼續拆分
ForkJoinTest leftForkJoin=new ForkJoinTest(arrys,startIndex,mid);
ForkJoinTest rightForkJoin=new ForkJoinTest(arrys,mid+1,endIndex);
leftForkJoin.fork();
rightForkJoin.fork(); //或者用invokeAll(leftForkJoin,rightForkJoin)
return leftForkJoin.join()+rightForkJoin.join();//合併所有子任務值
}
}
public static void main(String[] args){
long timeStart= System.currentTimeMillis();
int[] arrys=new int[40000];
for(int i=0;i<40000;i++){
arrys[i]=i;
}
ForkJoinPool pool=new ForkJoinPool();
ForkJoinTest forkJoinTest=new ForkJoinTest(arrys,0,arrys.length-1);
pool.invoke(forkJoinTest);
System.out.println(System.currentTimeMillis()-timeStart+"count:"+forkJoinTest.join());
}
}