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方法會等待子任務執行完並得到其結果。