摘要:ForkJoin线程池是将任务分割为子任务,有可能子任务还是很大,还需要进一步拆解,最终得到足够小的任务。

本文分享自华为云社区《ForkJoin线程池的学习和思考》,作者:breakDraw。

ForkJoin线程池在常规的java书籍里还是提到比较少的,毕竟是java8引入的产物。

首先这里简单解释一下forkJoin的运作原理, 本质上有点像归并计算。

  1. 他会将提交大任务按照一定规则拆解(fork)成多个小任务
  2. 当任务小到一定程度时,就会执行计算
  3. 执行完成时会和其他的小任务进行合并(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原理的更多相关文章

  1. exec 跟 source 差在哪?-- Shell十三问<第六问>

    exec 跟 source 差在哪?-- Shell十三问<第六问> 这次先让我们从 CU Shell 版的一个实例贴子来谈起吧: 例中的提问是: cd /etc/aa/bb/cc 可以执 ...

  2. 拜托!面试请不要再问我Spring Cloud底层原理[z]

    [z]https://juejin.im/post/5be13b83f265da6116393fc7 拜托!面试请不要再问我Spring Cloud底层原理 欢迎关注微信公众号:石杉的架构笔记(id: ...

  3. 《深入理解mybatis原理》 MyBatis的架构设计以及实例分析

    作者博客:http://blog.csdn.net/u010349169/article/category/2309433 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简 ...

  4. k3 Bos开发百问百答

              K/3 BOS开发百问百答   (版本:V1.1)           K3产品市场部       目录 一.基础资料篇__ 1 [摘要]bos基础资料的显示问题_ 1 [摘要]单 ...

  5. 《深入理解mybatis原理3》 Mybatis数据源与连接池

    <深入理解mybatis原理> Mybatis数据源与连接池 对于ORM框架而言,数据源的组织是一个非常重要的一部分,这直接影响到框架的性能问题.本文将通过对MyBatis框架的数据源结构 ...

  6. 《深入理解mybatis原理1》 MyBatis的架构设计以及实例分析

    <深入理解mybatis原理> MyBatis的架构设计以及实例分析 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单.优雅.本文主要讲述MyBatis的架构 ...

  7. 第九节: 利用RemoteScheduler实现Sheduler的远程控制 第八节: Quartz.Net五大构件之SimpleThreadPool及其四种配置方案 第六节: 六类Calander处理六种不同的时间场景 第五节: Quartz.Net五大构件之Trigger的四大触发类 第三节: Quartz.Net五大构件之Scheduler(创建、封装、基本方法等)和Job(创建、关联

    第九节: 利用RemoteScheduler实现Sheduler的远程控制   一. RemoteScheduler远程控制 1. 背景: 在A服务器上部署了一个Scheduler,我们想在B服务器上 ...

  8. Java 面试题问与答:编译时与运行时

    Java 面试题问与答:编译时与运行时 2012/12/17 | 分类: 基础技术, 职业生涯 | 5 条评论 | 标签: RUNTIME, 面试 分享到:58 本文作者: ImportNew - 朱 ...

  9. OpenGL快问快答

    OpenGL快问快答 本文内容主要来自对(http://www.opengl.org/wiki/FAQ)的翻译,随机加入了本人的观点.与原文相比,章节未必完整,含义未必雷同,顺序未必一致.仅供参考. ...

随机推荐

  1. Redis之品鉴之旅(七)

    分布式锁 1)阻塞锁: 尝试在redis中创建一个字符串结构缓存,方法传入的key,value为锁的过期时间timeout的时间戳. 若redis中没有这个key,则创建成功(即抢到锁),然后立即返回 ...

  2. MySQL表空间回收的正确姿势

    不知道大家有没有遇到这样的一种情况,线上业务在MySQL表上做增删改查操作,随着时间的推移,表里面的数据越来越多,表数据文件越来越大,数据库占用的空间自然也逐渐增长 为了缩小磁盘上表数据文件占用的空间 ...

  3. 【C++ Primer Plus】编程练习答案——第10章

    1 // chapter10_1_account.h 2 3 #ifndef LEARN_CPP_CHAPTER10_1_ACCOUNT_H 4 #define LEARN_CPP_CHAPTER10 ...

  4. DIVIDEMIX: LEARNING WITH NOISY LABELS AS SEMI-SUPERVISED LEARNING

    论文阅读: DIVIDEMIX: LEARNING WITH NOISY LABELS AS SEMI-SUPERVISED LEARNING 作者说明 版权声明:本文为博主原创文章,遵循CC 4.0 ...

  5. 面试官:Java从编译到执行,发生了什么?

    面试官:今天从基础先问起吧,你是怎么理解Java是一门「跨平台」的语言,也就是「一次编译,到处运行的」? 候选者:很好理解啊,因为我们有JVM. 候选者:Java源代码会被编译为class文件,cla ...

  6. Winform同步调用异步函数死锁原因分析、为什么要用异步

    1.前言 几年前,一个开发同学遇到同步调用异步函数出现死锁问题,导致UI界面假死.我解释了一堆,关于状态机.线程池.WindowsFormsSynchronizationContext.Post.co ...

  7. RPAaaS是什么?为何能够推进RPA人人可用?

    RPAaaS是什么?为何能够推进RPA人人可用? 助力中小企业快速实现自动化,RPAaaS加速"RPA人人可用"时代到来 相对传统RPA拥有更多优势,PRAaaS为RPA行业带来更 ...

  8. Java(44)JDK新特性之函数式接口

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201667.html 博客主页:https://www.cnblogs.com/testero ...

  9. python收集参数与解包

    收集任意数量的实参 def make_pizza(*toppings): """打印顾客点的所有配料""" print(toppings) ...

  10. 吴恩达深度学习课后习题第5课第1周第3小节: Jazz Improvisation with LSTM

    目录 Improvise a Jazz Solo with an LSTM Network Packages 1 - Problem Statement 1.1 - Dataset What are ...