Fork/Join是什么?

Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为大任务结果。其思想和MapReduce的思想非常类似。对于任务的分割,要求各个子任务之间相互独立,能够并行独立地执行任务,互相之间不影响。

Fork/Join的运行流程图如下:

我们可以通过Fork/Join单词字面上的意思去理解这个框架。Fork是叉子分叉的意思,即将大任务分解成并行的小任务,Join是连接结合的意思,即将所有并行的小任务的执行结果汇总起来。

工作窃取算法

ForkJoin采用了工作窃取(work-stealing)算法,若一个工作线程的任务队列为空没有任务执行时,便从其他工作线程中获取任务主动执行。为了实现工作窃取,在工作线程中维护了双端队列,窃取任务线程从队尾获取任务,被窃取任务线程从队头获取任务。这种机制充分利用线程进行并行计算,减少了线程竞争。但是当队列中只存在一个任务了时,两个线程去取反而会造成资源浪费。

工作窃取的运行流程图如下:

Fork/Join核心类

Fork/Join框架主要由子任务、任务调度两部分组成,类层次图如下。

  • ForkJoinPool

ForkJoinPool是ForkJoin框架中的任务调度器,和ThreadPoolExecutor一样实现了自己的线程池,提供了三种调度子任务的方法:

  1. execute:异步执行指定任务,无返回结果;
  2. invoke、invokeAll:异步执行指定任务,等待完成才返回结果;
  3. submit:异步执行指定任务,并立即返回一个Future对象;

    • ForkJoinTask

Fork/Join框架中的实际的执行任务类,有以下两种实现,一般继承这两种实现类即可。

  1. RecursiveAction:用于无结果返回的子任务;
  2. RecursiveTask:用于有结果返回的子任务;

Fork/Join框架实战

下面实现一个Fork/Join小例子,从1+2+…10亿,每个任务只能处理1000个数相加,超过1000个的自动分解成小任务并行处理;并展示了通过不使用Fork/Join和使用时的时间损耗对比。

  1. import java.util.concurrent.ForkJoinPool;
  2. import java.util.concurrent.RecursiveTask;
  3. public class ForkJoinTask extends RecursiveTask<Long> {
  4. private static final long MAX = 1000000000L;
  5. private static final long THRESHOLD = 1000L;
  6. private long start;
  7. private long end;
  8. public ForkJoinTask(long start, long end) {
  9. this.start = start;
  10. this.end = end;
  11. }
  12. public static void main(String[] args) {
  13. test();
  14. System.out.println("--------------------");
  15. testForkJoin();
  16. }
  17. private static void test() {
  18. System.out.println("test");
  19. long start = System.currentTimeMillis();
  20. Long sum = 0L;
  21. for (long i = 0L; i <= MAX; i++) {
  22. sum += i;
  23. }
  24. System.out.println(sum);
  25. System.out.println(System.currentTimeMillis() - start + "ms");
  26. }
  27. private static void testForkJoin() {
  28. System.out.println("testForkJoin");
  29. long start = System.currentTimeMillis();
  30. ForkJoinPool forkJoinPool = new ForkJoinPool();
  31. Long sum = forkJoinPool.invoke(new ForkJoinTask(1, MAX));
  32. System.out.println(sum);
  33. System.out.println(System.currentTimeMillis() - start + "ms");
  34. }
  35. @Override
  36. protected Long compute() {
  37. long sum = 0;
  38. if (end - start <= THRESHOLD) {
  39. for (long i = start; i <= end; i++) {
  40. sum += i;
  41. }
  42. return sum;
  43. } else {
  44. long mid = (start + end) / 2;
  45. ForkJoinTask task1 = new ForkJoinTask(start, mid);
  46. task1.fork();
  47. ForkJoinTask task2 = new ForkJoinTask(mid + 1, end);
  48. task2.fork();
  49. return task1.join() + task2.join();
  50. }
  51. }
  52. }

这里需要计算结果,所以任务继承的是RecursiveTask类。ForkJoinTask需要实现compute方法,在这个方法里首先需要判断任务是否小于等于阈值1000,如果是就直接执行任务。否则分割成两个子任务,每个子任务在调用fork方法时,又会进入compute方法,看看当前子任务是否需要继续分割成孙任务,如果不需要继续分割,则执行当前子任务并返回结果。使用join方法会阻塞并等待子任务执行完并得到其结果。

程序输出:

  1. test
  2. 500000000500000000
  3. 4992ms
  4. --------------------
  5. testForkJoin
  6. 500000000500000000
  7. 508ms

从结果看出,并行的时间损耗明显要少于串行的,这就是并行任务的好处。

尽管如此,在使用Fork/Join时也得注意,不要盲目使用。

  1. 如果任务拆解的很深,系统内的线程数量堆积,导致系统性能性能严重下降;
  2. 如果函数的调用栈很深,会导致栈内存溢出;

推荐阅读

干货:免费领取2TB架构师四阶段视频教程

面经:史上最全Java多线程面试题及答案

工具:推荐一款在线创作流程图、思维导图软件

分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。

Java7任务并行执行神器:Fork&Join框架的更多相关文章

  1. 013-多线程-基础-Fork/Join框架、parallelStream讲解

    一.概述 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 它同ThreadPoolExecut ...

  2. Java并发编程--Fork/Join框架使用

    上篇博客我们介绍了通过CyclicBarrier使线程同步,可是上述方法存在一个问题,那就是假设一个大任务跑了2个线程去完毕.假设线程2耗时比线程1多2倍.线程1完毕后必须等待线程2完毕.等待的过程线 ...

  3. Fork/Join框架与Java8 Stream API 之并行流的速度比较

    Fork/Join 框架有特定的ExecutorService和线程池构成.ExecutorService可以运行任务,并且这个任务会被分解成较小的任务,它们从线程池中被fork(被不同的线程执行)出 ...

  4. Java7任务并行执行神器:Fork&Join框架

    原 Java7任务并行执行神器:Fork&Join框架 2018年01月12日 17:25:03 Java技术栈 阅读数:426 标签: JAVAFORKJOIN 更多 个人分类: Java ...

  5. 使用Java7提供Fork/Join框架

    在Java7在.JDK它提供了多线程开发提供了一个非常强大的框架.这是Fork/Join框架.这是原来的Executors更多 进一步,在原来的基础上添加了并行分治计算中的一种Work-stealin ...

  6. 使用Java7提供的Fork/Join框架

    http://blog.csdn.net/a352193394/article/details/39872923 使用Java7提供的Fork/Join框架 2014-10-07 23:55 4818 ...

  7. 多线程(五) Fork/Join框架介绍及实例讲解

    什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过For ...

  8. JAVA中的Fork/Join框架

    看了下Java Tutorials中的fork/join章节,整理下. 什么是fork/join框架 fork/join框架是ExecutorService接口的一个实现,可以帮助开发人员充分利用多核 ...

  9. 聊聊并发(八)——Fork/Join框架介绍

      作者 方腾飞 发布于 2013年12月23日 | 被首富的“一个亿”刷屏?不如定个小目标,先把握住QCon上海的优惠吧!2 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 ...

随机推荐

  1. .NET/VB.NET: solving the error “The system cannot find the file specified.” “\Temp\.NETFramework,Version=v4.0.AssemblyAttributes.vb”

    Source Link Bumped into this error a while ago in Visual Studio 2010: Kind Error Number 80 Descripti ...

  2. JNDI 笔记

    原理:         在DataSource中事先建立多个数据库连接,保存在数据库连接池中.当程序访问数据库时,只用从连接池中取空闲状态的数据库连接即可,访问结束,销毁资源,数据库连接重新回到连接池 ...

  3. 基于vue2.0打造移动商城页面实践 vue实现商城购物车功能 基于Vue、Vuex、Vue-router实现的购物商城(原生切换动画)效果

    基于vue2.0打造移动商城页面实践 地址:https://www.jianshu.com/p/2129bc4d40e9 vue实现商城购物车功能 地址:http://www.jb51.net/art ...

  4. Intellij IDEA 智能补全的 10 个姿势,简直不能太牛逼!

    Java技术栈 www.javastack.cn 优秀的Java技术公众号 一年多前,栈长那时候刚从 Eclipse 转型 IDEA 成功,前面转了好多次,都是失败史,都是泪.. 后面我就在微信公众号 ...

  5. Python中dict的特点

    dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样.而list的查找速度随着元素增加而逐渐下降. 不过dict的查找速度快不是没有代价的,dict的缺点是占用内 ...

  6. 前端学习(三十一)canvas(笔记)

    canvas             画布    画图.做动画.做游戏===========================================    canvas就是新标签 必须获取绘图 ...

  7. 前端学习(二十七)存储&es6(笔记)

    cookie         存储    以站点为单位的.    必须配合服务器环境    不能跨浏览器    cookie有生命周期     默认是session        session    ...

  8. 调整Winfrom控件WebBrowser的默认浏览器内核版本

    一.问题解析: 今天在调试程序的时候,需要使用C#的客户端远程登录一个Web页面,用到了WebBrowser控件.但是却发现了一件很神奇的事情:当前浏览器使用的内核,可以通过访问下面这个网站获取:ht ...

  9. Vue学习笔记【28】——Vue路由(使用 children 属性实现路由嵌套)

    使用 children 属性实现路由嵌套   <div id="app">    <router-link to="/account"> ...

  10. pic16f877a的PWM实验学习

    遇到的问题,编译时找不到TRISC.一开始以为头文件中没有定义,发现定义了. 所以是自己创建工程的时候,设备类型选错了. #include <pic.h> __CONFIG(0xFF32) ...