Fork/Join框架和異步
定義:
Fork/Join框架是Java 7提供的一個用於並行執行任務的框架,是一個把大任務分割成若干個小任務,最終彙總每個小任務結果後得到大任務結果的框架。類似於遞歸或者分而治之的思想。
引用《Java併發編程的藝術》
Fork就是把一個大任務切分爲若干子任務並行的執行,Join就是合併這些子任務的執行結果,最後得到這個大任務的結
果。比如計算1+2+…+10000,可以分割成10個子任務,每個子任務分別對1000個數進行求和,最終彙總這10個子任務的結果
工作竊取算法 :
工作竊取(work-stealing)算法是指某個線程從其他隊列裏竊取任務來執行。
當大任務需要處理時,我們把其分割成多個子任務,存放在每個隊列中,並且每個線程處理不同隊列中的子任務,每當有線程(A)提前完成任務了,那麼(A)線程會去其他的隊列中竊取任務處理,這是A線程與當前的線程一起處理同一個隊列。
由此引出爲了減少竊取任務線程和被竊取任務線程之間的競爭,隊列採用雙端隊列。多線程處理同隊列的流程是:
被竊取任務線程永遠從雙端隊列的頭部拿任務執行,
竊取任務的線程(A)永遠從雙端隊列的尾部拿任務執行。
其優缺點:
工作竊取算法的優點:充分利用線程進行並行計算,減少了線程間的競爭。
工作竊取算法的缺點:在某些情況下還是存在競爭,比如雙端隊列裏只有一個任務時。並且該算法會消耗了更多的系統資源,比如創建多個線程和多個雙端隊列。
使用Fork/Join框架
需求是:計算1+2+3+4+......+100的結果
閾值設置爲10,希望每個子任務最大執行10個數的相加。
package com.JucPool;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
class MyTask extends RecursiveTask<Integer>{
private static final int THRESHOLD = 10; // 閾值
private int start;
private int end;
private int result;
public MyTask(int start, int end) {
this.start = start;
this.end = end;
}
@Override
protected Integer compute() {
if((end-start) <= THRESHOLD){
for(int i = start; i <= end; i++){
result +=i;
}
}else{
int mid = (start+end)>>1;
MyTask task1 = new MyTask(start, mid);
MyTask task2 = new MyTask(mid+1, end);
//執行子任務
task1.fork();
task2.fork();
//得到最後結果
result = task1.join()+task2.join();
}
return result;
}
}
public class demo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//創建線程池
ForkJoinPool joinPool = new ForkJoinPool();
//資源
MyTask myTask = new MyTask(1,100);
//執行任務
ForkJoinTask<Integer> submit = joinPool.submit(myTask);
System.out.println(submit.get());
}
}
使用ForkJoinTask資源需要繼承RecursiveTask(用於有返回結果的任務)--ForkJoinTask子類。
首先需要實現compute方法,我們在該方法中判斷任務的大小是否小於我們設置的閾值。如果小於閾值,就直接執行任務。如果不足夠小,就必須分割成兩個子任務,每個子任務在調用fork方法時,又會進入compute方法,看看當前子任務是否需要繼續分割成子任務,如果不需要繼續分割,則執行當前子任務並返回結果。使用join方法會等待子任務執行完並得到其結果。