先來簡單了解 Fork/Join 框架
Fork/Join
框架:就是在必要的情況下,將一個大任務,進行拆分(fork)成若干個小任務(拆到不可再拆時),再將一個個的小任務運算的結果進行 join 匯總。
Fork/Join 框架與傳統線程池的區別
采用“工作竊取”模式(work-stealing):當執行新的任務時它可以將其拆分分成更小的任務執行,並將小任務加到線程隊列中,然后再從一個隨機線程的隊列中偷一個並把它放在自己的隊列中。
相對於一般的線程池實現,fork/join框架的優勢體現在對其中包含的任務的處理方式上。在一般的線程池中,如果一個線程正在執行的任務由於某些原因無法繼續運行,那么該線程會處於等待狀態。而在fork/join框架實現中,如果某個子問題由於等待另外一個子問題的完成而無法繼續運行。那么處理該子問題的線程會主動尋找其他尚未運行的子問題來執行。這種方式減少了線程的等待時間,提高了性能。
JDK8 對 Fork/Join 的優化
JDK8 對 Fork/Join 的優化:主要是讓 Fork/Join 使用起來更加方便。對 Fork/Join 進行了封裝,簡化使用方式。
對於 JDK8 對 Fork/Join 的底層優化,這里不進行分析。
示例代碼
package hanwl.juc.day2; import java.time.Duration; import java.time.Instant; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; import java.util.stream.LongStream; import org.junit.Test; public class TestForkJoinPool { public static void main(String[] args) { Instant start = Instant.now(); ForkJoinPool pool = new ForkJoinPool(); ForkJoinTask<Long> task = new ForkJoinSumCalculate(0L, 50000000000L); Long sum = pool.invoke(task); System.out.println(sum); Instant end = Instant.now(); System.out.println("耗費時間為:" + Duration.between(start, end).toMillis());//166-1996-10590 } @Test public void test1(){ Instant start = Instant.now(); long sum = 0L; for (long i = 0L; i <= 50000000000L; i++) { sum += i; } System.out.println(sum); Instant end = Instant.now(); System.out.println("耗費時間為:" + Duration.between(start, end).toMillis());//35-3142-15704 } //java8 新特性 @Test public void test2(){ Instant start = Instant.now(); Long sum = LongStream.rangeClosed(0L, 50000000000L) .parallel() .reduce(0L, Long::sum); System.out.println(sum); Instant end = Instant.now(); System.out.println("耗費時間為:" + Duration.between(start, end).toMillis());//1536-8118 } } class ForkJoinSumCalculate extends RecursiveTask<Long>{ /** * */ private static final long serialVersionUID = -259195479995561737L; private long start; private long end; private static final long THURSHOLD = 10000L; //臨界值 public ForkJoinSumCalculate(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end - start; if(length <= THURSHOLD){ long sum = 0L; for (long i = start; i <= end; i++) { sum += i; } return sum; }else{ long middle = (start + end) / 2; ForkJoinSumCalculate left = new ForkJoinSumCalculate(start, middle); left.fork(); //進行拆分,同時壓入線程隊列 ForkJoinSumCalculate right = new ForkJoinSumCalculate(middle+1, end); right.fork(); // return left.join() + right.join(); } } }