Java 並發編程之ForkJoin框架
1、什麼是ForkJoin框架
ForkJoin框架是java的JUC包裡提供的,用於處理一些比較繁重的任務,會將這個大任務分為多個小任務,多個小任務處理完成後會將結果匯總給Result,體現的是一種“分而治之”的思想。第一步,拆分fork任務,將大任務分為多個小任務;第二步,歸並join,會將小任務的處理結果進行歸並為一個結果。
2、ForkJoinTask
ForkJoinTask是ForkJoin框架的提供的任務API,ForkJoinTask是一個抽象類,有兩個主要的實現類,RecursiveTask和RecursiveAction,其中RecursiveTask和RecursiveAction的主要區別是,RecursiveAction沒有返回值,而RecursiveTask是有返回值的
3、ForkJoinPool
ForkJoinPool類是forkjoin框架的線程池實現,基於ExecutorService接口。這個線程池是jdk1.7才加入的,用於管理線程,執行forkjoin的任務。對於線程池的使用,我們使用ThreadPoolExecutor比較多,可以在idea裡看一下uml類圖,可以看出ForkJoinPool和ThreadPoolExecutor實現差不多的。
ForkJoinPool() ForkJoinPool(int parallelism) ForkJoinPool(int parallelism, ForkJoinWorkerThreadFactory factory, UncaughtExceptionHandler handler, boolean asyncMode)
幾個重要的參數:
parallelism
:並行度,並行執行線程,可用指定,也可以不指定,不指定的情況,是根據cpu核數創建可用的線程ForkJoinWorkerThreadFactory
:創建線程的工廠實現UncaughtExceptionHandler
:因為未知異常中斷的回調處理asyncMode
:是否異步,默認情況是false
使用時候,可以直接創建ForkJoinPool,可以不傳參,不傳參的情況,默認指定的線程並行數為Runtime.getRunTime().availableProcessors();
,表示根據cpu核數創建可用線程數
ForkJoinPool forkJoinPool = new ForkJoinPool(); ArraySortTask task = new ArraySortTask(array , 0 , size); forkJoinPool.submit(task); task.get();
也是可用傳參,對並行度進行指定的public ForkJoinPool(int parallelism
), parallelism並行度,並行執行幾個線程
將forkjoin任務加入到FrokJoinPool線程池有幾種方式
execute()
:調用其 fork 方法在多個線程之間拆分工作。invoke()
:在ForkJoinPool線程池上調用invoke方法submit()
:返回一個Future對象,Future可以進行監控,任務完成後返回結果
4、打印斐波那契數列
ForkJoin框架可以用於一些遞歸遍歷的場景,對於斐波那契數列,你可以比較熟悉,因為在面試中有時候經常問到,斐波那契數列的特點就是最後一項的結果等於前面兩項的和
package com.example.concurrent.forkjoin; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.ForkJoinTask; import java.util.concurrent.RecursiveTask; /** * <pre> * 斐波那契數列 * </pre> * <p> * <pre> * @author nicky.ma * 修改記錄 * 修改後版本: 修改人: 修改日期: 2021/10/12 16:22 修改內容: * </pre> */ public class Fibonacci extends RecursiveTask<Integer>{ private int n; public Fibonacci(int n) { this.n = n; } @Override protected Integer compute() { if (n <= 1) return n; Fibonacci f1 = new Fibonacci(n - 1); f1.fork(); Fibonacci f2 = new Fibonacci(n - 2); f2.fork(); return f1.join() + f2.join(); } public static void main(String[] args) throws ExecutionException, InterruptedException { ForkJoinPool pool = new ForkJoinPool(); for (int i = 0; i< 10; i++) { ForkJoinTask task = pool.submit(new Fibonacci(i)); System.out.println(task.get()); } } }
5、ForkJoin歸並排序
面試題:快速實現對一個長度百萬的數組的排序
難點:可以使用歸並排序,多線程如何組織實現歸並排序
package com.example.concurrent.forkjoin; import java.util.Arrays; import java.util.Random; import java.util.concurrent.ExecutionException; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.RecursiveAction; /** * <pre> * 大數組排序 * </pre> * <p> * <pre> * @author mazq * 修改記錄 * 修改後版本: 修改人: 修改日期: 2021/10/12 17:04 修改內容: * </pre> */ public class ArraySortTask extends RecursiveAction{ final long[] array; final int lo, hi; ArraySortTask(long[] array, int lo, int hi) { this.array = array; this.lo = lo; this.hi = hi; } ArraySortTask(long[] array) { this(array, 0, array.length); } @Override protected void compute() { if (hi - lo < THRESHOLD) // 少於閥值,使用Arrays.sort 快排 sortSequentially(lo, hi); else { /* 歸並排序 */ // 取中間值 int mid = (lo + hi) >>> 1; // 拆分任務 invokeAll(new ArraySortTask(array, lo, mid), new ArraySortTask(array, mid, hi)); // 歸並結果 merge(lo, mid, hi); } } // implementation details follow: static final int THRESHOLD = 1000; void sortSequentially(int lo, int hi) { Arrays.sort(array, lo, hi); } void merge(int lo, int mid, int hi) { long[] buf = Arrays.copyOfRange(array, lo, mid); for (int i = 0, j = lo, k = mid; i < buf.length; j++) array[j] = (k == hi || buf[i] < array[k]) ? buf[i++] : array[k++]; } public static void main(String[] args) throws ExecutionException, InterruptedException { int size = 10_000; long[] array = new long[size]; Random random = new Random(); for (int i = 0; i< size; i++) { array[i] = random.nextInt(); } ForkJoinPool forkJoinPool = new ForkJoinPool(); ArraySortTask task = new ArraySortTask(array , 0 , size); forkJoinPool.submit(task); task.get(); for (long a : array) { System.out.println(a); } } }
總結
本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!
推薦閱讀:
- Java並發編程之Fork/Join框架的理解
- Java多線程高並發中的Fork/Join框架機制詳解
- Java並發中的Fork/Join 框架機制詳解
- 輕輕松松吃透Java並發fork/join框架
- java代碼實現C盤文件統計工具