前言

ForkJoinPool罕用于将大工作合成(Fork)成若干小工作并行执行,而后再把每个小工作的执行后果合并起来(Join)失去大工作的最终后果。上面是示意图(ps:盗网上网上盗的图,禁止套娃!)

ForkJoinPool通常配合ForkJoinTask一起应用,ForkJoinTask代表一个工作,它是个抽象类,它的常见子类有RecursiveTask和RecursiveAction,其中RecursiveTask有返回值,RecursiveAction无返回值。

上面举个简略栗子来阐明ForkJoinPool的应用场景。
场景:计算整数1~10000000的和。

最传统的形式就是间接for循环累加,但这里咱们也能够用ForkJoinPool实现并行计算,以此晋升性能(数据量很大时)。代码如下:

import java.time.Duration;import java.time.Instant;import java.util.concurrent.ForkJoinPool;import java.util.concurrent.RecursiveTask;import java.util.stream.LongStream;public class ForkJoinPoolDemo {    public static void main(String[] args) {        long[] nums = LongStream.rangeClosed(1, 10000000).toArray();        ForkJoinPool pool = new ForkJoinPool();        Instant before = Instant.now();        Long result = pool.invoke(new ComputeSumTask(nums, 0, nums.length - 1));        Instant after = Instant.now();        pool.shutdown();        System.out.println(result);        System.out.println("cost time(ms) : " + Duration.between(before, after).toMillis());        System.out.println("Now let's watch traditional for-loop cost time below :");        before = Instant.now();        result = forLoopCompute(nums);        after = Instant.now();        System.out.println(result);        System.out.println("cost time(ms) : " + Duration.between(before, after).toMillis()); }    private static Long forLoopCompute(long[] nums) {        long sum = 0;        for (long num : nums) {             sum += num;        }        return sum;    }    static class ComputeSumTask extends RecursiveTask<Long> {        private int start;        private int end;        private long[] nums;        ComputeSumTask(long[] nums, int start, int end) {             this.nums = nums;             this.start = start;             this.end = end;        }        @Override        protected Long compute() {            // 当须要计算的数字个数小于10000时,进化成间接for循环计算            // 留神这里的阈值要适合,太小的话容易导致内存溢出,太大的话施展不了ForkJoinPool的劣势。            if (end - start < 10000) {                long sum = 0;                for (int i = start; i <= end; i++) {                    sum += nums[i];                }                return sum;            } else {                int mid = (end - start) / 2 + start;                ComputeSumTask leftTask = new ComputeSumTask(nums, start, mid);                ComputeSumTask rightTask = new ComputeSumTask(nums, mid + 1, end);                leftTask.fork();                rightTask.fork();                return leftTask.join() + rightTask.join();            }        }    }}

输入后果:

后果很奇怪,传统for循环耗时反而更短,这是因为10000000数据量还不够大,没有施展ForkJoinPool的劣势,并且因为fork和join的操作反而耗费了性能。咱们再加个0看看成果。


能够看到,这时候应用ForkJoinPool性能就晋升了。

实现原理

先看看类图构造:

@sun.misc.Contendedpublic class ForkJoinPool extends AbstractExecutorService {}

它跟ThreadPoolExecutor一样,也继承了AbstractExecutorService,阐明它也是一种线程池。

再来看看要害属性:

今天再剖析,先去跟妹子聊天了,嘻嘻~