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); } } }
总结
本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!