栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

分治思想ForkJoin原理分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

分治思想ForkJoin原理分析

笔记目录
  • 1.任务类型分类
    • 1.1 CPU密集型任务
    • 1.2 I/O密集型任务
  • 2.分治算法
  • 3.ForkJoin
    • 3.1 ForkJoin的架构组成
      • 3.1.1 ForkJoinPool 分治任务线程池
      • 3.1.2 ForkJoinTask 分治任务
    • 3.2 ForkJoin工作机制

1.任务类型分类 1.1 CPU密集型任务

CPU密集型任务的特点就是计算密集,对CPU的依赖相当高,对于这样的任务线程分配的最佳实践就是CPU核心数的2倍,如果设置过多会导致线程上下文切换十分频繁。

1.2 I/O密集型任务

IO密集型任务属于IO频繁,例如数据库的访问、文件访问、网络传输等,这些操作不会耽误CPU的资源但是会消耗IO资源,任务的执行时长较长。这样的任务线程分配最佳实践就是多余CPU的核心数好几倍。但是对于IO密集型的任务需要压测来进行最优的分配。

2.分治算法

分而治之的指导思想就是将一个规模为N的问题进行分解拆分为K个小的子问题,这些子问题相互独立并且原理性质相同,甚至子问题还可以继续拆分,最后汇总得到结果。

3.ForkJoin

ForkJoin是对线程池ThreadPoolExecutor的补充,它将大任务进行细化拆分最终合并为结果返回。ForkJoin适合CPU密集型的任务。ForkJoin是对AbstractExecutorService抽象类的补充和扩展。

3.1 ForkJoin的架构组成 3.1.1 ForkJoinPool 分治任务线程池

ForkJoinPool适用于执行ForkJoinTask任务的线程池,和传统的线程池不一样,它底层维护了一个WorkQueue数组来避免提交任务和线程任务的时候减少碰撞。
ForkJoinPool构造有4个核心参数:

           - int parallelism:设置线程数量,如果不指定就使用默认的CPU核心数。
           - ForkJoinWorkerThreadFactory factory:线程工厂,可以不指定,有默认的实现。
           - UncaughtExceptionHandler handler:异常处理器,任务报错后由它处理。
           - boolean asyncMode:队列的工作模式选择,true表示FIFO,false表示FILO模式。

ForkJoinPool的任务提交方式:

           - execute:没有返回结果,不仅支持ForkJoinTask还支持Runnable任务。
           - invoke:有返回结果,接受ForkJoinTask任务,如果传入null,则抛出空指针。
           - submit:有返回结果,支持ForkJoinTask、Runnable、Callable任务。
3.1.2 ForkJoinTask 分治任务

ForkJoinTask是ForkJoinPool的实际任务承载体,定义了任务执行的具体逻辑。ForkJoinTask继承自Future接口,所以它具有future的一些功能,例如异步返回值。
它有2个核心的方法:fork()、join()。一个用于任务的提交,一个用于任务结果的获取。

           - fork():提交任务。
           - join():获取任务执行结果,如果任务没有执行完毕那么线程将会阻塞直到获取结果。

我们开发一般只需要继承ForkJoinTask类或者其子类,覆盖相应的方法即可。

           - RecursiveAction:递归执行,不需要返回结果的任务。
           - RecursiveTask:递归执行,需要返回结果。
3.2 ForkJoin工作机制
     - 通过调用ForkJoinPool的invoke()或者submit()方法提交任务时,ForkJoinPool会根据一定的规则将任务提交到一个工作队列中,如果这个任务在工作中创建了子任务,那么子任务会提交到工作线程所绑定的对应队列中去。
     - ForkJoinPool的每一个工作线程都维护了一个工作队列`WorkQueue`,它是一个双端队列Deque,里面存放的节点就是任务对象ForkJoinTask的子类。
     - 当每个工作线程在运行中创建了子任务,将子任务放入自己线程维护的双端队列中,自己使用FILO后入先出的模式进行任务执行,这是为了提供一个`工作窃取`的设计。
     - 每个工作任务在处理自己队列中的任务时,会尝试窃取其它线程的工作队列的任务,当然这肯定是采用FIFO模式窃取,避免了和别的线程发生竞争。
     - 当线程遇到join()时,如果该任务的返回值还没有,就会等待。
     - 如果工作线程把自己的任务执行完毕,而且也没有可窃取的任务时,工作线程就会睡眠。
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1003750.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号