ForkJoinPool分支合併框架 核心思想->代碼演示

線程池架構Fork-Join 框架

就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 彙總。

Fork-Join 框架

工作竊取 模式(work-stealing)

當執行新的任務時它可以將其拆分分成更小的任務執行,並將小任務加到線程隊列中,當該線程隊列沒有需要執行的任務時,再從一個隨機線程的隊列中偷一個並把它放在自己的隊列中。

相對於一般的線程池實現,fork-join框架的優勢體現在對其中包含的任務的處理方式上.在一般的線程池中,如果一個線程正在執行的任務由於某些原因無法繼續運行,那麼該線程會處於等待狀態。而在fork-join框架實現中,如果某個子問題由於等待另外一個子問題的完成而無法繼續運行。那麼處理該子問題的線程會主動尋找其他尚未運行的子問題來執行.這種方式減少了線程的等待時間,提高了性能。

工作竊取模式

代碼演示

package com.xiaoqiang;

import java.time.Duration;
import java.time.Instant;
import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
/**
 * 本案例適用於大量操作
 * 若少量數據可直接操作
 * 程序執行速度受臨界值較大
 * 請選擇合理的臨界值
 * @author xiaoqiang
 * @time 2017-7-5
 */

public class ForkJoin extends RecursiveTask<Long> {
    private static final long serialVersionUID = 7633953255462137626L;
    private long start;// 開始值
    private long end;// 結束值
    private static final long THURSHOLD = Math.abs(new Random().nextInt());// 臨界值

    public ForkJoin(long start, long end) {
        this.start = start;
        this.end = end;
    }

    /**
     * 結束值與開始至之差小於臨界值時 程序繼續把大任務劃分爲小任務
     */

    @Override
    protected Long compute() {
        long temp = end - start;
        if (temp <= THURSHOLD) {
            long sum = 0L;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        } else {
            long middle = (start + end) / 2;
            // 遞歸調用
            ForkJoin left = new ForkJoin(start, middle);
            ForkJoin right = new ForkJoin(++middle, end);
            left.fork(); // 進行拆分 繼續執行判斷
            right.fork();
            return left.join() + right.join();// 合併結果集
        }
    }
    public static void main(String[] args) {
        Instant time1 = Instant.now();//JAVA8新類  可以使用System.currentTimeMillis() 替代
        ForkJoinPool pool = new ForkJoinPool();
        ForkJoinTask<Long> task = new ForkJoin(0L, 50000000000L);
        long sum = pool.invoke(task);
        Instant time2 = Instant.now();
        System.out.println("分割後耗費時間:" + Duration.between(time1, time2).toMillis() + "毫秒");
        sum = 0L;
        Instant time3 = Instant.now();
        for (long i = 0L; i <= 50000000000L; i++) {
            sum += i;
        }
        Instant time4 = Instant.now();
        System.out.println("未分割耗費時間:" + Duration.between(time3, time4).toMillis() + "毫秒");
//      分割後耗費時間:8284毫秒
//      未分割耗費時間:15552毫秒
//      若數據較少 則分割會額外耗費時間

    }

}
發佈了39 篇原創文章 · 獲贊 35 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章