最近在看線程池代碼時發現了一個ForkJoinPool類,可以看一下線程池的繼承關系,頂層的Executor接口,提供了一個execute()方法,我們常用的ExecutorService接口也繼承自Executor接口,定義了一些額外的方法,下面呢就是AbstractExecutorService類,在這個類中實現了三個submit方法,而創建線程池的ThreadPoolExecutor類就繼承自AbstractExecutorService,而同時ForkJoinPool也繼承了AbstractExecutorService,對於這個ForkJoinPool以往不太了解,簡單學習了一下進行記錄。下面是線程池繼承體系。
ForkJoin並發框架是一個用於並行執行任務的框架,適用於計算密集型,它可以把一個任務分成若干個小任務,也可以把各個小任務的結果進行合並,所以很適合計算如從1加到100000這種操作。
ForkJoin並發框架:fork 分解任務 +join 將結果合並,當然,對於一些沒有返回結果的任務,可以只fork不合並。也就是僅僅fork划分任務,但不join進行任務結果的合並。
java中實現ForkJoin的幾個類
ForkJoinPool:繼承了線程池的接口,因此也是一種線程池的實現,不同之處在於我們平常創建的線程池只有一個任務隊列,而ForkJoinPool可以為每個線程分配任務隊列,同時一個線程可以從其他線程的任務隊列中獲取任務,因為有些線程可以很快的完成了任務,有些可能完成的比較慢,這是,完成快的就可以從完成慢的線程的任務隊列中獲取任務(從任務隊列后端獲取)。
ForkJoinTask:也就是ForkJoinPool要完成的任務,提供了fork和join 方法,有兩個常用的抽象子類RecursiveTask和RecursiveAction,都提供了抽象方法compute,我們可以重寫compute方法進行任務的划分,RecursiveTask提供返回值,而RecursiveAction不提供返回值。
通過一段代碼來理解forkjoin的用處和用法,計算從0加到10000000...。
定義一個類繼承RecursiveTask
public class ForkJoinCal extends RecursiveTask<Long> { private long start; private long end; private static final long THRESHOLD = 10000L;//臨界值 public ForkJoinCal(long start, long end) { this.start = start; this.end = end; } @Override protected Long compute() { long length = end -start; if(length<=THRESHOLD){ long sum =0; for (long i = start; i <=end ; i++) { sum+=i; } return sum; }else { long middle =(start+end)/2; ForkJoinCal left = new ForkJoinCal(start, middle); left.fork(); ForkJoinCal right = new ForkJoinCal(middle + 1, end); right.fork(); return left.join()+right.join(); } } }
主方法進行測試
public class ForkJoinTest { public static void main(String[] args) { ForkJoinPool pool = new ForkJoinPool(2); ForkJoinCal task = new ForkJoinCal(0, 1000000000L); Long sum = pool.invoke(task); System.out.println(sum); } }
本文暫時使了解ForkJoin是什么,怎么用,下面會對一些原理進行分析。