JUC之Fork/Join框架

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章