ForkJoin 学习使用笔记
Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架
I. 背景
在日常的业务需求中,经常出现的批量查询,批量写入等接口的提供,一般来说,最简单最low的方式就是写一个for循环来一次执行,但是当业务方对接口的性能要求较高时,就比较尴尬了
通常可以想到的方式是采用并发操作,首先想到可以实现的方式就是利用线程池来做
通常实现方式如下
1 | // 1. 创建线程池 |
用上面的这种方式并没有什么问题,我们接下来考虑的是如何使用ForkJoin框架来实现类似的功能
II. ForkJoin 基本知识
Fork: 将大任务拆分成若干个可以并发执行的小任务
Join: 合并所有小任务的执行结果
1. 任务分割
ForkJoinTask
: 基本任务,使用forkjoin框架必须创建的对象,提供fork,join操作,常用的两个子类
RecursiveAction
: 无结果返回的任务RecursiveTask
: 有返回结果的任务
说明:
fork
: 让task异步执行join
: 让task同步执行,可以获取返回值- ForkJoinTask 在不显示使用ForkJoinPool.execute/invoke/submit()方法进行执行的情况下,也可以使用自己的fork/invoke方法进行执行
2. 结果合并
ForkJoinPool
执行 ForkJoinTask
,
- 任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。
- 当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务
三中提交方式:
execute
异步,无返回结果submit
异步,有返回结果 (返回Future<T>
)invoke
同步,有返回结果 (会阻塞)
III. 使用说明
结合两个场景,给出使用姿势
1. 累加
实现从 start - end 的累加求和
首先是定义一个CountTask
来实现求和
首先是确定任务分割的阀值,当 end-start
的差值大于阀值时,将任务一分为二
1 | public class CountTask extends RecursiveTask<Integer> { |
调用case
1 | @Test |
输出结果:
1 | thread: Thread[ForkJoinPool.commonPool-worker-0,5,main] start: 51 end: 75 |
2. 排序
int 数组进行排序
同样先定义一个SortTask, 主要是为了演示ForkJoin的使用姿势,具体的排序和合并的逻辑比较简陋的实现了一下(这块不是重点)
1 | public class SortTask extends RecursiveTask<List<Integer>> { |
测试case和上面基本一样,我们改用 invoke 替换上面的 submit
1 | @Test |
输出结果
1 | thread: Thread[ForkJoinPool.commonPool-worker-0,5,main] sort: [34, 3123, 3414, 4512] |
IV. 其他
参考
个人博客: Z+|blog
基于hexo + github pages搭建的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
声明
尽信书则不如,已上内容,纯属一家之言,因本人能力一般,见识有限,如发现bug或者有更好的建议,随时欢迎批评指正
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840