Fork/Join是什么?

Fork意思是分叉,Join为合并。Fork/Join是一个将任务分割并行运行,然后将最终结果合并成为大任务的结果的框架,父任务可以分割成若干个子任务,子任务可以继续分割,提供我们一种方便的并行任务功能,满足实际场景的业务需求,思想类似于MapReduce。任务的分割必须保证子任务独立,不会相互依赖结果。

从哪里开始?

Fork/Join框架主要有如下接口和类:

  • ForkJoinPool:一个线程池,用于执行调度分割的任务,实现了ExecutorService接口。提供三种执行任务的方式:

1、execute:最原生的执行方式,以异步执行,并且无返回结果。
2、submit:异步执行,有返回结果,返回结果是封装后的Future对象。
3、invoke和invokeAll:异步执行,有返回结果,会等待所有任务执行执行完成,返回的结果为无封装的泛型T。

  • ForkJoinTask:抽象的分割任务,提供以分叉的方式执行,以及合并执行结果。
  • RecursiveAction:异步任务,无返回结果。通常自定义的任务要继承,并重写compute方法,任务执行的就是compute方法。
  • RecursiveTask:异步任务,有返回结果。通常自定义的任务要继承,并重写compute方法,任务执行的就是compute方法。

核心类图

从核心类图看出,要想开始一个分割的并行任务,可以创建一个ForkJoinPool线程池,同时创建无返回结果的任务RecursiveAction或有返回结果的任务RecursiveTask,最后调用线程池ForkJoinPool的execute或submit或invoke方法执行任务,完成后合并结果。

实例

我们以一个有返回结果的并行任务实例进行测试。计算从起始值到结束值得连续数的累加结果,利用Fork/Join框架。并对比普通计算和并行计算的耗时差异。

package com.misout.forkjoin;import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;/** * 计算从起始值到结束值得连续数的累加结果,利用Fork/Join框架 * @author Misout * @date 2018-01-13 16:06:44 */ public class SumTask extends RecursiveTask<Long> { private static final long serialVersionUID = 4828818665955149519L; /** 每个任务最多允许计算的数字个数阈值,超过这个阈值,任务进行拆分 */ private static final long THRESHOLD = 1000L; /** 起始值 */ private Long startNumber; /** 结束值 */ private Long endNumber; public SumTask(Long startNumber, Long endNumber) { this.startNumber = startNumber; this.endNumber = endNumber; } /** * 累加数的个数超过阈值1000个,拆分成2个子任务执行。子任务继续作拆分。计算完,合并结果。 */ @Override protected Long compute() { if(startNumber > endNumber) { System.out.println("start number should be smaller than end number"); return 0L; } if(endNumber - startNumber < THRESHOLD) { return this.getCount(startNumber, endNumber); } else { Long mid = (startNumber + endNumber) / 2; RecursiveTask<Long> subTask1 = new SumTask(startNumber, mid); RecursiveTask<Long> subTask2 = new SumTask(mid + 1, endNumber); subTask1.fork(); subTask2.fork(); return subTask1.join() + subTask2.join(); } } /** * 普通累加执行方法 * @param start 起始数 * @param end 结束数 * @return 累加和 */ protected Long getCount(Long start, Long end) { Long sum = 0L; for(long i = start; i <= end; i++) { sum += i; } return sum; } public static void main(String[] args) { ForkJoinPool forkJoinPool = new ForkJoinPool(); Long start = 5L; Long end = 3463434L; SumTask task = new SumTask(start, end); Long startTime = System.currentTimeMillis(); Long sum = forkJoinPool.invoke(task); Long endTime = System.currentTimeMillis(); System.out.println("fork/join : sum = " + sum + ", cost time = " + (endTime - startTime) + "ms"); startTime = System.currentTimeMillis(); Long sum2 = task.getCount(start, end); endTime = System.currentTimeMillis(); System.out.println("normal : sum = " + sum2 + ", cost time = " + (endTime - startTime) + "ms"); } } 

说明:SumTask继承RecursiveTask,并实现了compute方法。在compute方法中会进行任务分割,并继续生成子任务,子任务仍然以分割的方式运行。

运行结果对比:

fork/join : sum = 5997689267885, cost time = 290ms
normal : sum = 5997689267885, cost time = 41ms

注意事项:任务拆分的深度最好不要太多,否则很容易因创建的线程过多影响系统性能。

work-stealing规则

在Java的API说明中提到,ForkJoinPool线程池与ThreadPoolExecutor线程池不同的地方在于,ForkJoinPool善于利用窃取工作执行加快任务的总体执行速度。实际上,在ForkJoinPool线程池中,若一个工作线程的任务队列为空没有任务执行时,便从其他工作线程中获取任务主动执行。为了实现工作窃取,在工作线程中维护了双端队列,窃取任务线程从队尾获取任务,被窃取任务线程从队头获取任务。这种机制充分利用线程进行并行计算,减少了线程竞争。但是当队列中只存在一个任务了时,两个线程去取反而会造成资源浪费。

ForkJoinPool工作窃取图

转载于:https://www.cnblogs.com/Joy-Hu/p/10876628.html

Java并行任务框架Fork/Join相关推荐

  1. JUC组件扩展(二)-JAVA并行框架Fork/Join(四):监控Fork/Join池

    Fork/Join 框架是为了解决可以使用 divide 和 conquer 技术,使用 fork() 和 join() 操作把任务分成小块的问题而设计的.主要实现这个行为的是 ForkJoinPoo ...

  2. java 中的fork join框架

    文章目录 ForkJoinPool ForkJoinWorkerThread ForkJoinTask 在ForkJoinPool中提交Task java 中的fork join框架 fork joi ...

  3. Java 并发 (13) -- Fork/Join 框架

    文章目录 1. 简介 2. 精讲 1. 什么是 Fork/Join 框架 2. 工作窃取算法 3. Fork/Join 框架的设计 4. 使用 Fork/Join 框架 5. Fork/Join 框架 ...

  4. Java 7:Fork / Join框架示例

    Java 7中的Fork / Join Framework专为可分解为较小任务的工作而设计,并将这些任务的结果组合起来以产生最终结果. 通常,使用Fork / Join Framework的类遵循以下 ...

  5. 【Java】java中的Fork/Join

    1.概述 视频:java中的Fork/Join Fork/Join是什么? Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任 ...

  6. join left 大数据_Java并发编程笔记-JDK内置并行执行框架Fork/Join

    Fork/Join由来-分而治之思想 分而治之:对于一个比较复杂的任务,如果可以很自然地将其分解为多个子任务,这些子任务互相独立且与原问题性质相同,递归地处理这些子任务,然后将各个子任务的结果合并得到 ...

  7. Java:使用Fork / Join框架的Mergesort

    此项的目的是显示一个Fork / Join RecursiveAction的简单示例,而不是过多地研究合并合并的可能优化方法,或者比使用Exkutor / Join Pool优于现有的基于Java 6 ...

  8. java forkjoinpool_Java并发——Fork/Join框架与ForkJoinPool

    为了防止无良网站的爬虫抓取文章,特此标识,转载请注明文章出处.LaplaceDemon/ShiJiaqi. http://www.cnblogs.com/shijiaqi1066/p/4631466. ...

  9. Java中的Fork / Join框架的简要概述

    Fork / Join框架是使用并发分治法解决问题的框架. 引入它们是为了补充现有的并发API. 在介绍它们之前,现有的ExecutorService实现是运行异步任务的流行选择,但是当任务同质且独立 ...

最新文章

  1. 完整恢复模式下的备份/恢复
  2. Vue安装配置以及入门案例
  3. 车坛刮起了一阵文艺风
  4. C#三层架构第五课之DBUtil层设计
  5. MySQL在线DDL工具pt-osc
  6. django mysql5.7_GitHub - qiubiteme/DjangoBloger: 一个Django2.0+mysql57,实现的响应式博客
  7. .NET | 多线程下的调用上下文 : CallContext
  8. stm32 web get 参数_纯进口mpv销量排行榜 迈巴赫vs680商务车参数
  9. 三、Dart Hello World
  10. MOQL--操作数(Operand) (一)
  11. ML/DL-复习笔记【十】- 分组卷积和深度可分离卷积的区别
  12. 估计理论(1):最小方差无偏估计(第2章)
  13. python--查询PG数据库
  14. 客户端的gzip解压
  15. 新手如何Reverces(3自动化逆向篇)
  16. 服务器lsass占用内存_记一次服务器病毒查杀过程:lsass.exe占用内存高
  17. jsp实现文件的上传
  18. C语言中的%f和%lf的区别
  19. Kettle基本使用(四) —— 应用的使用
  20. 采用SpringBoot发送简单、抄送、密送、带附件邮件

热门文章

  1. 信息检索及DM必备知识总结:luncene
  2. 人脸检测的harr检测函数
  3. [ICPC 北京 2017 J题]HihoCoder 1636 Pangu and Stones
  4. mysql无法导入函数和存储过程解决方法
  5. Object-C 中的Selector 概念
  6. tilecache2.11在windows apache2.22安装部署
  7. [ warning] [vmusr:vmtoolsd] Failed registration of app type 2 (Signals)
  8. 11步提高代码质量和整体工作效率
  9. Python中静态方法的实现
  10. flink的kafka各种依赖区别