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
明天再分析,先去跟妹子聊天了,嘻嘻~繼承