在 Java7引入的诸多新特性中,Fork/Join 框架无疑是重要的一项。JSR166旨在标准化一个实质上可扩展的框架,以将并行计算的通用工具类组织成一个类似java.util中Collection一样的包。其目标是使之对开发人员易用且易维护,同时该框架也旨在并行计算地高质量实现。目前已经有多个新的类和接口被添加到该框架中了。

  该新特性主要是解决Java社区中对于如synchronized,wait和notify等操作的低级别的话题活动的需求。Fork/Join框 架被设计成可以容易地将算法并行化、分治化。开发人员曾多次想用自己(在非底层实现)的并发机制实现这一目标,因此新框架的想法是提供标准化和效率最高的并发工具协助开发人员实现各种多线程应用。其所需的类和接口都位于java.util.concurrent包中。

Fork/Join 框架

  正如先前所说,Fork/Join框架是Java7中新增的一项特性,也是Java7平台的其中一项主要改进。与普通Thread相比,Executor框架对多线程开发的支持要好得多。在实际情况中,很多时候我们都需要面对经典的"分治"问题。要解决这类问题,主要任务通常被分解为多个任务块(分解阶段),其后每一小块任务被独立并行计算。一旦计算任务完成,每一快的结果会被合并或者解决(解决阶段)。

  "分治"问题可以很容易地通过Callable线程的Executor接口来解决。通过为每个任务实例化一个Callable实例,并在ExecutorService类中汇总计算结果来得出最终结果可以实现这一目的。那么自然而然想到的问题就是,如果这一接口已经做得不错了,我们为什么还需要Java 7的其他框架?

  使用ExecutorService和Callable的主要问题是,Callable实例在本质上是阻塞的。一旦一个Callable实例开始执行,其他所有Callable都会被阻塞。由于队列后面的Callable实例在前一实例未执行完成的时候不会被执行,因此许多资源无法得到利用。Fork/Join框架被引入来解决这一并行问题,而Executor解决的是并发问题(译者注:并发和并行的区别就是一个处理器同时处理多个任务和多个处理器或者是多核的处理器同时处理多个不同的任务)。

Fork/Join框架中的"工作窃取(Work stealing)"
Fork/Join框架在java.util.concurrent包中加入了两个主要的类:

  * ForkJoinPool:这个类实现了ExecutorService和工作窃取算法。它管理工作者线程,并提供任务的状态信息,以及任务的执行信息。

  * ForkJoinTask:
这个类是一个将在ForkJoinPool中执行的热内的基类。

  通常为了实现Fork/Join任务,需要实现以下两个类之一的子类。

* RecursiveAction:用于任务没有返回结果的场景。

  * RecursiveTask
用于任务有返回结果的场景

  ForkJoinPool类是ForkJoinTask实例的执行者,ForkJoinPool的主要任务就是”工作窃取”,其线程尝试发现和执行其他任务创建的子任务。ForkJoinTask实例与普通Java线程相比是非常轻量的。一
旦ForkJoinTask被启动,就会启动其子任务并等待它们执行完成。执行者ForkJoinPool负责将任务赋予线程池中处于等待任务状态的另一线程。线程池中的活动线程会尝试执行其他任务所创建的子任务。ForkJoinPool会尝试在任何时候都维持与可用的处理器数目一样数目的活动线程数

  除了几个其他API方法以外,ForkJoinTask有两个主要的方法:

  * fork () – 这个方法决定了ForkJoinTask的异步执行,凭借这个方法可以创建新的任务。
  * join () –当一个主任务等待其创建的多个子任务的完成执行。

Fork/Join框架执行的任务具有以下限制:

  • 任务只能使用fork()和join()操作当做同步机制。如果使用其他的同步机制,工作者线程就不会执行任务。
  • 任务不能执行I/0操作,比如文件数据的读取与写入。
  • 任务不能抛出非运行时异常(Checked Exception),必须在代码中处理这些异常。

    ForkJionTask主要包括以下方法:

  • invokeAll():执行主任务创建的多个子任务,这是一个同步调用,当一个主任务等待它的子任务是,执行这个主任务的工作者线程接受另一个等待执行的任务开始执行。
  • complete(reslut):结束任务的执行并返回任务的结果。这个方法接受一个对象,对象的类型是泛型参数,然后在任务调用jion操作时返回这个对象作为结果。这一过程采用了推荐的异步任务来返回任务结果。
  • get().获取任务的结果。

    ForkJionPool主要包括以下方法:

  • execute(Runnabletask).发送任务给ForkJionPool类,使用Runnable对象时ForkJionPool类不采用工作窃取算法,仅仅在使用ForkJionTask类时才采用工作窃取算法。

  分支/合并的完整过程如下.

Java 7 Fork/Join 实例

  本节中,我们将描述一个通过Java7引入的Fork/Join框架进行n个自然数求和的例子。如前所述,本例的目的是将n个自然数求和的计算工作分解为更小的计算单元,再合并得出最终结果。检验和数的逻辑保持不变。
计算过程的基本原则是将n划分为更小的值来分别独立计算和数。整个遍历过程包括将n划分为1到n/2和(n+2)+1到n两部分,以及分别计算每一部分的和。

ForkJoinTask类如下定义:

  EvaluateSumForkJoinTask
类扩展自递归结果处理类RecursiveTask,用于创建ForkJoinTask实例。RecursiveTask是泛型类,本例中设置为
Integer。EvaluateSumForkJoinTask重载了compute ()方法,该方法负责创建出新的任务分支,并合并计算结果。既然主要问题可以被分解为两个大块,我们就创建两个工作者线程myWorker1和myWorker2,分别分配较小的n值给它们。一旦n值被减小到2,任务就没必要再并行化分解了。并行化停止条件可以根据具体的n值进行调整,以达到更好的并行效果。

  客户端类用于管理ForkJoinPool,并负责调用主任务。ForkJoinPool实例基于当前硬件条件下可用处理器数量进行配置。示例程序运行的机器配有一个含2个处理器单元的双核处理器上。invoke()方法将对检验前n个(500个)自然数和的任务进行分解,该任务会轮流调用
EvaluateSumForkJoinTask类的compute()方法,EvaluateSumForkJoinTask类也扩展自
RecursiveTask。


计算结果比较

  使用Fork/Join的计算过程由多个工作者线程代理,共同工作以计算和数。其计算结果和单线程的实现模式相比较得出以下结果:

N值

单线程模型耗时 (ms)

分支/合并模型耗时 (ms)

备注

20

4

7

本例中,分支/合并模型由于较小的n值耗时较长。对于非常小规模的问题而言,并行化未必值得。

100

15

6

在这三个例子中,分支/合并模型由于使用了多处理器核心导致耗时较短。

500

124

6

1000

285

7

  值得关注的一点是,单线程模型中CPU利用率比Fork/Join模型要小,如下所示:
单线程模型


分支/合并模型


结论

  本文通过单线程模型到Java7引入的Fork/Join模型的演化,讨论了Java平台并行的编程特性。Java5引入的Executor是一大进步,但由于其阻塞特性无法被应用于并行计算。因此Java
7引入的Fork/Join框架扮演了重要角色。本文通过一个非常简单的例子解释了并发及并行编程的概念,并通过两种方式结果数据的比较得出结论。

Java 7 Fork/Join 框架的更多相关文章

  1. Java并发——Fork/Join框架

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

  2. Java并发——Fork/Join框架与ForkJoinPool

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

  3. Java使用Fork/Join框架来并行执行任务

    现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机.多核处理器已被广泛应用.在未来,处理器的核心数将会发展的越来越多. 虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并未这 ...

  4. 我的Java开发学习之旅------>Java使用Fork/Join框架来并行执行任务

    现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机.多核处理器已被广泛应用.在未来,处理器的核心数将会发展的越来越多. 虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并未这 ...

  5. Java Fork/Join 框架

    简介 从JDK1.7开始,Java提供Fork/Join框架用于并行执行任务,它的思想就是讲一个大任务分割成若干小任务,最终汇总每个小任务的结果得到这个大任务的结果. 这种思想和MapReduce很像 ...

  6. Java并发编程(07):Fork/Join框架机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Fork/Join框架 Java提供Fork/Join框架用于并行执行任务,核心的思想就是将一个大任务切分成多个小任务,然后汇总每个小任务 ...

  7. Fork/Join框架详解

    Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架.Fork/Join框架要完成两件事情: 1.任务分 ...

  8. 初步了解Fork/Join框架

    框架介绍 Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个子任务,最终汇总每个子任务的执行结果以得到大任务结果的框架.Fork/Join框架要完成两件事 ...

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

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

随机推荐

  1. Akamai在内容分发网络中的算法研究(翻译总结)

    作者 | 钱坤 钱坤,腾讯后台开发工程师,从事领域为流媒体CDN相关,参与腾讯TVideo平台开发维护. 原文是<Algorithmic Nuggets in Content Delivery& ...

  2. 20155214 2016-2017-2 《Java程序设计》第5周学习总结

    20155214 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 1.错误会被包装为可抛出的对象,继承自java.lang.Throwable类. 2.可以利 ...

  3. 【Electron】Electron开发入门

    Electron简介: Electron提供了丰富的本地(操作系统)的API,使你能够使用纯JavaScript来创建桌面应用程序,并且跨平台(win,mac,linux等各种PC端平台).与其它各种 ...

  4. 通过php动态传数据到highcharts

    1:在平时工作中,在对数据进行展示的时候,是直接通过后台提供的接口来获取json串,用来展示.今天别人问怎么在本地演示一下请求的动态数据. 2:在本地搭建环境,我用的WampServer,下载地址:h ...

  5. Codeforces 392C Yet Another Number Sequence (矩阵快速幂+二项式展开)

    题意:已知斐波那契数列fib(i) , 给你n 和 k , 求∑fib(i)*ik (1<=i<=n) 思路:不得不说,这道题很有意思,首先我们根据以往得出的一个经验,当我们遇到 X^k ...

  6. mac下CSV文件用FileReader、FileWriter读写乱码

      先说下windows的excel文件搬到mac下打开为什么会显示乱码.    在win下,excel采用GBK编码,1个汉字是存为2个字节,而mac下各种软件广泛默认使用UTF-8编码方式,如在e ...

  7. Spring MVC__自定义日期类型转换器

    WEB层采用Spring MVC框架,将查询到的数据传递给APP端或客户端,这没啥,但是坑的是实体类中有日期类型的属性,但是你必须提前格式化好之后返回给它们.说真的,以前真没这样做过,之前都是一口气查 ...

  8. 利用 force recovery 解决服务器 crash 导致 MySQL 重启失败的问题

    小明同学在本机上安装了 MySQL 5.7.17 配合项目进行开发,并且已经有了一部分重要数据.某天小明在开发的时候,需要出去一趟就直接把电脑关掉了,没有让 MySQL 正常关闭,重启 MySQL 的 ...

  9. win7下用SSH连接linux虚拟机

    本文来自转载:原文 [需求] 在win7环境下用SSH(SecureShell)连接本地的一台虚拟机上ubuntu(11.10)系统  [环境] win7,ubuntu,vmware(8.0) [方案 ...

  10. struts2 之 struts2类型转换

    1. 在struts2中,相比servlet来时,获取数据时,程序员没有进行手动的类型转换,类型转换工作都有struts2来完成处理,但愿对于自定义类型数据,struts2不会帮助我们完成类型转换工作 ...