Java ForkJoinPool分支合併框架

一、ForkJoinPool 分支合併框架

ForkJoinPool類實現了ExecutorService接口,因此也屬於線程池,是一種特殊的線程池。

ForkJoinPool這個工具類從Java7 纔開始提供的,優勢在於,可以充分利用多cpu,多核cpu的優勢,把一個大任務(fork)成若干小任務,把若干小任務放到多個處理器核心上並行執行;當這些小任務執行完成之後,最終彙總(Join)每個小任務結果後得到大任務結果的框架。從而實現用少量的線程,完成大數量的任務。

1、ThreadPoolExecutor 與 ForkJoinPool區別

ForkJoinPool與ThreadPoolExecutor兩個都實現了Executor和ExecutorService接口。

ForkJoinPool它使用了一個無限隊列來保存需要執行的任務,而線程的數量則是通過構造函數傳入,如果沒有向構造函數中傳入希望的線程數量,那麼當前計算機可用的CPU數量會被設置爲線程數量作爲默認值。使用ForkJoinPool能夠使用數量有限的線程來完成非常多的具有父子關係的任務,

ThreadPoolExecutor能夠提高線程的可管理性,通過重用已存在的線程,降低線程創建和銷燬造成的消耗;提高系統響應速度。但是,由於ThreadPoolExecutor中的Thread無法選擇優先執行子任務,所以不能完成父子關係的任務。

 

2、使用方法

創建 ForkJoinPool 實例,然後調用ForkJoinPool的 submit(ForkJoinTask<T> task) 或invoke(ForkJoinTask<T> task)方法來執行指定任務了。其中 ForkJoinTask代表一個可以並行、合併的任務。

ForkJoinTask是一個抽象類,它還有兩個抽象子類:RecusiveAction和RecusiveTask。其中RecusiveTask代表有返回值的任務,而RecusiveAction代表沒有返回值的任務。

實例一:沒有返回值的“大任務”(打印1-3000之間的整數)- RecusiveAction

public class ForkJoinPoolDemo1 {

    public static void main(String[] args) throws Exception {
        PrintTask task = new PrintTask(1, 300);
        // 創建ForkJoinPool實例,並執行分割任務,
        // 若參數爲空,則當前計算機可用的CPU數量會被設置爲線程數量作爲默認值
        ForkJoinPool pool = new ForkJoinPool(4);
        pool.submit(task);
        // 線程阻塞,等待所有任務完成
        pool.awaitTermination(2, TimeUnit.SECONDS);
        // 關閉線程池
        pool.shutdown();
    }
}

class PrintTask extends RecursiveAction {
    private static final int THRESHOLD = 50; //一次最多隻能打印50個數
    private int start;
    private int end;

    public PrintTask(int start, int end) {
        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();
        }
    }
}

實例二:有返回值的“大任務”(對一個長度爲300的數組元素進行累加求和)- RecusiveTask

public class ForkJoinPoolDemo2 {
    public static void main(String[] args) throws Exception {
        int[] arr = new int[300];
        Random random = new Random();
        int total = 0;
        // 初始化100個數組元素
        for (int i = 0, len = arr.length; i < len; i++) {
            int temp = random.nextInt(20);
            // 對數組元素賦值,並將數組元素的值添加到sum總和中
            total += (arr[i] = temp);
        }
        System.out.println("初始化數組總和:" + total);

        SumTask task = new SumTask(arr, 0, arr.length);
        // 創建ForkJoinPool,這個是jdk1.8提供的功能
        ForkJoinPool pool = ForkJoinPool.commonPool();
        Future<Integer> future = pool.submit(task); //提交分解的SumTask 任務
        System.out.println("多線程執行結果:" + future.get());
        //關閉線程池
        pool.shutdown();
    }
}

class SumTask extends RecursiveTask<Integer> {
    private static final int THRESHOLD = 20; //每個小任務 最多隻累加20個數
    private int arry[];
    private int start;
    private int end;

    public SumTask(int[] arry, int start, int end) {
        super();
        this.arry = arry;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        int sum = 0;
        //當end與start之間的差小於threshold時,開始進行實際的累加
        if (end - start < THRESHOLD) {
            for (int i = start; i < end; i++) {
                sum += arry[i];
            }
            return sum;
        } else {
            //當end與start之間的差大於threshold,即要累加的數超過20個時候,將大任務分解成小任務
            int middle = (start + end) / 2;
            SumTask left = new SumTask(arry, start, middle);
            SumTask right = new SumTask(arry, middle, end);
            //並行執行兩個小任務
            left.fork();
            right.fork();
            //把兩個小任務累加的結果合併起來
            return left.join() + right.join();
        }
    }
}

    

參考文章:

ForkJoinPool 分支/ 合併框架實戰與原理分析

 

—— Stay Hungry. Stay Foolish. 求知若飢,虛心若愚。

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