六问六答理解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)的翻译,随机加入了本人的观点.与原文相比,章节未必完整,含义未必雷同,顺序未必一致.仅供参考. ...
随机推荐
- dubbo微服务架构
架构 节点角色说明 调用关系说明 服务容器负责启动,加载,运行服务提供者. 服务提供者在启动时,向注册中心注册自己提供的服务. 服务消费者在启动时,向注册中心订阅自己所需的服务. 注册中心返回服务提供 ...
- WireShark高级用法
报文注释 分组注释 尽量使用英文注释 时间显示 显示实际时间 抓包过滤器 按照规则抓取报文 显示过滤器 按照规则显示报文 自动生成过滤条件:做为过滤器应用 着色规则 默认 可自定义着色规则 追踪数据流 ...
- css3中的陌生词汇
Transform transform属性是静态属性,一旦写到style里面,将会直接显示作用,无任何变化过程.transform的主要用途是用来做元素的特殊变形. 关于图形变形的基础条件当中的原点设 ...
- Java安全之ClassLoader
Java安全之ClassLoader 类加载机制 Java中的源码.java后缀文件会在运行前被编译成.class后缀文件,文件内的字节码的本质就是一个字节数组 ,它有特定的复杂的内部格式,Java类 ...
- idea使用gitee的小坑
1. 账号配置 账号配置登陆时提示 *** is not a valid login name: Email support only. 翻译:只能支持邮箱登录 解决方法:在gitee网站上查看自己配 ...
- JVM探针与字节码技术
JVM探针是自jdk1.5以来,由虚拟机提供的一套监控类加载器和符合虚拟机规范的代理接口,结合字节码指令能够让开发者实现无侵入的监控功能.如:监控生产环境中的函数调用情况或动态增加日志输出等等.虽然在 ...
- Java - 你的 Java 代码有这些坏味道吗?
列举一些 Java 开发中常见的"不良实践",来源于代码扫描(https://github.com/pmd/pmd),和诸君一起学习参考: 1 - 关闭资源 CloseResour ...
- Python:安装opencv出现错误Could not find a version that satisfies the requirement numpy==1.13.3 (from versions: 1.14.5, 1.14.6, 1.15.0rc2, 1.15.0, 1.15.1, 1.15.2, 1.15.3, 1.15.4, 1.16.0rc1, 1.16.0rc2,
安装opencv的时候,出现numpy的版本不匹配,卸载了不匹配的版本,重新安装却是一点用都没有,后面尝试了一下这里的提示pip更新,居然安装成功了,看来pip的版本过低真是误事啊. 报错是: Cou ...
- Centos7 配置JDK 提示 /lib/ld-linux.so.2: bad ELF interpreter: No such file or direct
解决办法:yum install glibc.i686
- SQL实例_11Oracle基本操作
前言导读 本章介绍了在正常使用Oracle数据库之前进行的常规操作 本章语句的运行需要子啊PLSQL软件中运行 本章导入导出语句需要在虚拟环境中直接运行 1 Oracle创建表空间和用户 --1 创建 ...