ForkJoinPool经常使用于将大任务分解(Fork)成若干小任务并行执行,而后再把每一个小任务的执行结果合并起来(Join)获得大任务的最终结果。下面是示意图(ps:盗网上网上盗的图,禁止套娃!)
ForkJoinPool一般配合ForkJoinTask一块儿使用,ForkJoinTask表明一个任务,它是个抽象类,它的常见子类有RecursiveTask和RecursiveAction,其中RecursiveTask有返回值,RecursiveAction无返回值。java
下面举个简单栗子来讲明ForkJoinPool的使用场景。
场景:计算整数1~10000000的和。ide
最传统的方式就是直接for循环累加,但这里咱们也能够用ForkJoinPool实现并行计算,以此提高性能(数据量很大时)。代码以下:oop
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看看效果。this
能够看到,这时候使用ForkJoinPool性能就提高了。spa
先看看类图结构:线程
@sun.misc.Contended public class ForkJoinPool extends AbstractExecutorService { }
它跟ThreadPoolExecutor同样,也继承了AbstractExecutorService,说明它也是一种线程池。code
再来看看关键属性:blog
明天再分析,先去跟妹子聊天了,嘻嘻~继承