前言
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,阐明它也是一种线程池。
再来看看要害属性:
今天再剖析,先去跟妹子聊天了,嘻嘻~