六问六答理解ForkJoin原理
摘要:ForkJoin线程池是将任务分割为子任务,有可能子任务还是很大,还需要进一步拆解,最终得到足够小的任务。
本文分享自华为云社区《ForkJoin线程池的学习和思考》,作者:breakDraw。
ForkJoin线程池在常规的java书籍里还是提到比较少的,毕竟是java8引入的产物。
首先这里简单解释一下forkJoin的运作原理, 本质上有点像归并计算。
- 他会将提交大任务按照一定规则拆解(fork)成多个小任务
- 当任务小到一定程度时,就会执行计算
- 执行完成时会和其他的小任务进行合并(join), 逐步将所有小结果合成一个大结果。

可以看这个forkJoinTask的实现伪代码,即如果想使用forkJoin并发执行任务,需要自己把任务继承RecursiveTask,作为forkJoin池的submit对象:
public class ForkJoinTask extends RecursiveTask<任务参数> {
public ReckonTask(任务参数) {
}
@Override
protected File compute() {
if(根据任务参数判断任务是否足够小) {
计算,返回
} else {
拆分成子任务1和子任务2
任务1.fork();
任务2.fork();
结果1 = 任务1.join();
结果2 = 任务2.join();
返回结果1+结果2;
}
}
}
然后实际上整个forkjoin的细节非常多,这里我通过给自己提好几个问题,来逐步理解forkJoin的原理:
Q: forkJoin中各个线程是如何获取那些小任务的呢?
A:他是通过工作密取的方式获取。(java并发那本书里提到过工作密取workSteal,原来是用在这了)
- 假设我们给forkJoin设置3个工作线程,那么就会有3个工作队列, 注意,这个队列是双端队列。
- 每当执行任务时,如果不满足小任务的条件,他会fork出2个子任务,并push进自己的工作队列中。
- 每个工作线程不断取自己队头的任务执行。
- 关键点:如果自己队列里没有数据,则会从其他队列的队尾取数据。
Q: fork时具体发生了什么?
A:是一个异步的操作, 就是向当前线程队列中添加这个fork出来任务,能放进去的话就返回,不会等待。
注意,默认fork出的任务是先默认给自己的。 当自己做不完时,才可能被别人取走!

Q: join是什么含义?什么时候做的?
A:见实现forkJoin任务接口时的代码:

可以看到时每次fork完之后, 通过join,来获取子task的结果,获取到之后,再合并计算,返回结果。
Q: join这个阻塞过程是怎么做的?如果把线程挂起,那这个线程岂不是无法工作了?
A:首先,之前fork时,新的子任务已经被放入队列了。
每个子任务都有一个任务状态。
当调用该子任务的join时, 会循环判断他的状态
如果这个子任务状态未完成, 则从自身队列或其他人的队列中取出新的任务执行,因此进入了下一层的exec()操作。
如果发现子任务状态更新为了完成(这个更新动作可能是自己线程完成的,也可能是别的线程完成的,反正这个任务的状态实现了同步和可见), 则将结果返回给上层。
因此join的本质是一个递归的过程, 任务没完成的话,他就取其他任务继续递归往下执行。
更详细的可以看这个链接fork+join过程详细解读
Q: forkJoin存放任务的时候,怎么保证不会出现并发问题?比如同时往队尾插入的话
A:
- n个工作线程是通过数组存放的(即有一个工作线程数组)
- sun.misc.Unsafe操作类直接基于操作系统控制层在硬件层面上进行原子操作,它是ForkJoinPool高效性能的一大保证,类似的编程思路还体现在java.util.concurrent包中相当规模的类功能实现中。

Q: forkJoin应用在哪吗?
A:java8 stream的parallel并发功能就是基于forkJoin做的, parallelStream实现的forkJoin拆解任务和执行任务的接口, 默认用机器所有CPU数量的forkJoin线程池。
如果需要限制线程数量,可以用
new forkJoin(线程数).submit(()->(list.stream().parallel().map()…)); 即可
六问六答理解ForkJoin原理的更多相关文章
- exec 跟 source 差在哪?-- Shell十三问<第六问>
exec 跟 source 差在哪?-- Shell十三问<第六问> 这次先让我们从 CU Shell 版的一个实例贴子来谈起吧: 例中的提问是: cd /etc/aa/bb/cc 可以执 ...
- 拜托!面试请不要再问我Spring Cloud底层原理[z]
[z]https://juejin.im/post/5be13b83f265da6116393fc7 拜托!面试请不要再问我Spring Cloud底层原理 欢迎关注微信公众号:石杉的架构笔记(id: ...
- 《深入理解mybatis原理》 MyBatis的架构设计以及实例分析
作者博客:http://blog.csdn.net/u010349169/article/category/2309433 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简 ...
- k3 Bos开发百问百答
K/3 BOS开发百问百答 (版本:V1.1) K3产品市场部 目录 一.基础资料篇__ 1 [摘要]bos基础资料的显示问题_ 1 [摘要]单 ...
- 《深入理解mybatis原理3》 Mybatis数据源与连接池
<深入理解mybatis原理> Mybatis数据源与连接池 对于ORM框架而言,数据源的组织是一个非常重要的一部分,这直接影响到框架的性能问题.本文将通过对MyBatis框架的数据源结构 ...
- 《深入理解mybatis原理1》 MyBatis的架构设计以及实例分析
<深入理解mybatis原理> MyBatis的架构设计以及实例分析 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单.优雅.本文主要讲述MyBatis的架构 ...
- 第九节: 利用RemoteScheduler实现Sheduler的远程控制 第八节: Quartz.Net五大构件之SimpleThreadPool及其四种配置方案 第六节: 六类Calander处理六种不同的时间场景 第五节: Quartz.Net五大构件之Trigger的四大触发类 第三节: Quartz.Net五大构件之Scheduler(创建、封装、基本方法等)和Job(创建、关联
第九节: 利用RemoteScheduler实现Sheduler的远程控制 一. RemoteScheduler远程控制 1. 背景: 在A服务器上部署了一个Scheduler,我们想在B服务器上 ...
- Java 面试题问与答:编译时与运行时
Java 面试题问与答:编译时与运行时 2012/12/17 | 分类: 基础技术, 职业生涯 | 5 条评论 | 标签: RUNTIME, 面试 分享到:58 本文作者: ImportNew - 朱 ...
- OpenGL快问快答
OpenGL快问快答 本文内容主要来自对(http://www.opengl.org/wiki/FAQ)的翻译,随机加入了本人的观点.与原文相比,章节未必完整,含义未必雷同,顺序未必一致.仅供参考. ...
随机推荐
- GitHub 和 Gitee 开源免费 10 个超赞后台管理面板,看完惊呆了!
软件工程师在实际项目开发中不可避免需要依赖一些前后端的后台管理系统框架,而不是从零开始一点点的搭建,浪费人力.目前市面上有很多开放源码.且免费的后台管理面板,样式色彩也比较丰富美观. 今天整理 ...
- 通俗易懂,Layui前端框架!
前言 layui 是一款采用自身模块规范编写的前端 UI 框架,遵循原生 HTML/CSS/JS 的书写与组织形式,门槛极低,拿来即用.其外在极简,却又不失饱满的内在,体积轻盈,组件丰盈,从核心代 ...
- 记一次Kafka服务器宕机的真实经历!!
大家好,我是冰河~~ 估计节前前祭拜服务器不灵了,年后服务器总是或多或少的出现点问题.不知是人的问题,还是风水问题.昨天下班时,跟运维小伙伴交代了好几遍:如果使用Docker安装Kafka集群的话,也 ...
- xLua中C#调用Lua
C#调用Lua 一.前提 这里使用的是XLua框架,需要提前配置xlua,设置加载器路径: 可以参考之前的Blog:<xlua入门基础>: 二.C#调用Lua全局变量 lua中所有的全局变 ...
- 解决VM 与 Device/Credential Guard 不兼容
通过命令关闭Hyper-V(控制面板关闭Hyper-V起不到决定性作用,要彻底关闭Hyper-V) 以管理员身份运行Windows Powershell (管理员)(Windows键+X) 运行下面命 ...
- CAD图DWG解析WebGIS可视化技术分析总结
背景 AutoCAD是国际上著名的二维和三维CAD设计软件,用于二维绘图.详细绘制.设计文档和基本三维设计.现已经成为国际上广为流行的绘图工具..dwg文件格式成为二维绘图的事实标准格式. 但由于Au ...
- 消息队列那么多,为什么建议深入了解下RabbitMQ?
你为啥要在项目中选择xxx消息中间件? 提起消息队列,也许你的脑海里会不自觉地蹦出好多概念:JMS.Kafka.RocketMQ.AMQP.RabbitMQ.ActiveMQ.Pulsar.Redis ...
- Sentinel-Go 源码系列(一)|开篇
大家好呀,打算写一个 Go 语言组件源码分析系列,一是为了能学习下 Go 语言,看下别人是怎么写 Go 的,二是也掌握一个组件. 本次选择了 Sentinel-Go,一是对 Java 版本的 Sent ...
- Jupyter Notebook配置多个kernel
Jupyter Notebook配置多个kernel 前言: 在anaconda下配置了多个环境,而Jupiter Notebook只是安装在base环境下,为了能在Jupiter Notebook中 ...
- mysqld_exporter监控mysql信息
mysqld_exporter监控mysql信息 一.背景 二.prometheus接入mysqld_exporter 1.安装mysqld_exporter 2.创建mysqld_exporter用 ...