JUC併發編程(十四)-分支合併ForkJoin

14、分支合併:ForkJoin

14.1. 什麼是ForkJoin

​ ForkJoin,任務切分、合併操作。大數據中的mapreduce ,就是任務切分,結果合併。原理如下圖所示:

在這裏插入圖片描述

14.2. 工作竊取

工作竊取

A 任務1 --> 任務2 --> 任務3 --> 任務4 A領先執行完成 ,幫B執行任務(從B任務的尾部開始竊取任務執行)!

B 任務1 --> 任務2 任務3 任務4

工作開始從頭,竊取從尾,有效提高速度,雙端隊列

在這裏插入圖片描述

14.3. 核心類

14.3.1. ForkJoinPool

1、ForkJoinPool

ForkJoinPool ,是實現了ExecutorService的任務池,將任務ForkJoinTask放到ForkJoinPool中,去運行線程。 通過隊列來執行,找到實現接口的類

在這裏插入圖片描述

​ 而ForkJoinPool 中存在一個內部類,工作隊列WorkQueue,是ForkJoinPool 的 一個內部類。每一個線程都有一個 WorkQueue !

14.3.2. ForkJoinTask

2、ForkJoinTask

ForkJoinTask 是一個抽象類,代表正在 ForkJoinPool 中運行的 任務,它有三個主要的方法:

在這裏插入圖片描述

fork: 安排任務異步執行,簡單的說,就是創建一個子任務。

join:當任務完成後獲取去返回的計算結果!

invoke:開始執行!如果計算沒有完畢,就會等待!

14.3.3. RecursiveTask

3、RecursiveTask

**ForkJoinTask的一個重要子類:**遞歸 RecursiveTask

在這裏插入圖片描述

其中有個計算方法compute

/**
     * The main computation performed by this task.
     * @return the result of the computation
     */
    protected abstract V compute();

我們一般要繼承RecursiveTask類,重寫compute方法,如下示例:

MyRecursiveTask

package com.interview.concurrent.stream;

import java.util.concurrent.RecursiveTask;

/**
 * @author yangxj
 * @description 描述:遞歸任務,泛型是計算後返回的結果類型
 * @date 2020/2/24 15:56
 */
public class MyRecursiveTask extends RecursiveTask<Long> {
    private long start; //開始值
    private long end; //結束值
    private static final long temp = 10000L; //中間值

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

    @Override
    protected Long compute() {

        if (end - start <= temp) {
            long sum = 0L;
            for (long i = start; i <= end; i++) {
                sum += i;
            }
            return sum;
        }else{
            //獲取中間值
            long middle = (start + end)/2;
           /**
           * fork()會不斷的循環
           */
            //第一個任務
            MyRecursiveTask rightTask = new MyRecursiveTask(start,middle);
            rightTask.fork();
            //第二個任務
            MyRecursiveTask leftTask = new MyRecursiveTask(middle+1, end);
            leftTask.fork();

            //合併結果
            return rightTask.join() + leftTask.join();
        }
    }
}

fork()會不斷的循環。

ForkJoin代碼編寫模型:

1、創建ForkJoinPool;

2、創建ForkJoinTask;

3、ForkJoinPool對象調用invoke執行,並將ForkJoinTask對象放入ForkJoinPool中

示例:計算1到10,0000,0000的和,通過三種方式,比較性能

package com.interview.concurrent.stream;

import java.util.concurrent.ForkJoinPool;
import java.util.stream.LongStream;

/**
 * @author yangxj
 * @description 描述:計算1到10,0000,0000的和
 * @date 2020/2/24 15:40
 */
public class ForkJoinDemo {

    public static void main(String[] args) {
        //calculateNormal();   //time:781 sum:500000000500000000
        //calculateForkJoin(); //time:724 sum:500000000500000000
        calculateStream();     //time:473 sum:500000000500000000
    }

    // 正常測試
    public static void calculateNormal(){
        long startTime = System.currentTimeMillis();
        long sum = 0L;
        for (long i = 0L; i <= 10_0000_0000L; i++) {
            sum += i;
        }

        long endTime = System.currentTimeMillis();
        System.out.println("time:"+(endTime-startTime)+" sum:"+sum);
    }

    // ForkJoin測試
    public static void calculateForkJoin(){
        long startTime = System.currentTimeMillis();

       /** 
       *1、創建ForkJoinPool;
       */
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        /** 
       *2、創建ForkJoinTask;
       */
        MyRecursiveTask recursiveTask = new MyRecursiveTask(0L,10_0000_0000L);
        /** 
       3、ForkJoinPool對象調用invoke執行,並將ForkJoinTask對象放入ForkJoinPool中;
       */
        long sum = forkJoinPool.invoke(recursiveTask);

        long endTime = System.currentTimeMillis();
        System.out.println("time:"+(endTime-startTime)+" sum:"+sum);
    }

    // Stream並行流測試
    public static void calculateStream(){
        long startTime = System.currentTimeMillis();

        long sum = LongStream.rangeClosed(0L,10_0000_0000L).parallel().reduce(0L,Long::sum);

        long endTime = System.currentTimeMillis();
        System.out.println("time:"+(endTime-startTime)+" sum:"+sum);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章