在JAVA7之前,并行处理数据非常麻烦。第一,你得明确把包含数据的数据结构分成若干份。第二,你要将每个子部分分配给一个独立的线程。第三,你要在恰当的时候对它们进行同步避免不希望的竞争条件,等待所有线程完成,最后把这些部分结果合并起来。在Java 7引入了分支/合并框架,让这些操作更稳定、更不容易出错。

分支/合并框架的目的是以递归的方式将可以并行的任务拆分为更小的任务,然后将每个子任务的结果合并起来生成整体结果。要把子任务提交到ForkJoinPool必须创建RecursiveTask<R>的子类。需要实现它唯一的抽象方法 protected abstract R compute();  在这个方法中定义了将任务拆分成子任务的逻辑,以及无法拆分时生成单个子任务结果的逻辑。

计算1到10000000的和

/*** Desc:Fork/Join框架的目的是以递归方式将可以并行的任务拆分为更小的任务,然后将每个子任务的结果合并起来生成一个整体结果。* 要把任务提交到ForkJoinPool必须创建RecursiveTask<T> 的一个子类* * @author wei.zw* @since 2016年7月6日 下午9:27:56* @version v 0.1*/
public class ForkJoinSumCalculator extends RecursiveTask<Long> {/**  */private static final long serialVersionUID = -8013303660374621470L;private final long[] numbers;private final int start;private final int end;private static final long THRESHOLD = 1000;/*** @param numbers* @param start* @param end*/public ForkJoinSumCalculator(long[] numbers, int start, int end) {super();this.numbers = numbers;this.start = start;this.end = end;}/*** @param numbers*/public ForkJoinSumCalculator(long[] numbers) {super();this.numbers = numbers;this.start = 0;this.end = numbers.length;}/*** @see java.util.concurrent.RecursiveTask#compute()*/@Overrideprotected Long compute() {int length = end - start;if (length <= THRESHOLD) {return computeSequentially();}ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(numbers, start, start + length / 2);leftTask.fork();ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(numbers, start + length / 2, end);rightTask.fork();Long rightResult = 0L;try {rightResult = rightTask.get();} catch (Exception e) {}Long leftResult = leftTask.join();return leftResult + rightResult;}/*** * @return* @author wei.zw*/private Long computeSequentially() {long sum = 0;for (int i = start; i < end; i++) {sum += numbers[i];}return sum;}public static void main(String[] args) {long[] numbers = LongStream.rangeClosed(1, 10000000).toArray();long start = System.currentTimeMillis();System.out.println(new ForkJoinPool().invoke(new ForkJoinSumCalculator(numbers)) + " 耗时:"+ (System.currentTimeMillis() - start));}}

  

结果是:50000005000000 耗时:37

优化后的

/*** @see java.util.concurrent.RecursiveTask#compute()*/@Overrideprotected Long compute() {int length = end - start;if (length <= THRESHOLD) {return computeSequentially();}ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(numbers, start, start + length / 2);leftTask.fork();ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(numbers, start + length / 2, end);Long rightResult = rightTask.compute();Long leftResult = leftTask.join();return leftResult + rightResult;}

  

计算结果是:50000005000000 耗时:25

使用Fork/Join框架的最佳做法:

  • 对一个任务调用join方法会阻塞调用方,直到该任务作出结果。因此,又必须要在两个子任务的计算都开始之后再调用它。
  • 不应该在RecursiveTask内部使用ForkJoinPool的invoke方法,应该直接调用compute或者fork方法
  • 对子任务调用fork方法可以将这个子任务排进ForkJoinPool。同时对左右两边的子任务都调用似乎很自然,但是这样做的效率比直接对其中一个调用compute方法低。这样做可以为其中一个子任务重用同一线程,从而避免在线程池中多分配一个任务造成的开销。

看完了基本示例,在分析一下源码;首先看一下RecursiveTask,通过名称可以知道这是一个递归Task.源码很简单

public abstract class RecursiveTask<V> extends ForkJoinTask<V> {private static final long serialVersionUID = 5232453952276485270L;//计算结果V result;//抽象的计算方法protected abstract V compute();//获取计算结果public final V getRawResult() {return result;}//设置计算结果protected final void setRawResult(V value) {result = value;}//执行计算protected final boolean exec() {result = compute();return true;}}

 RecursiveTask源码看完以后,继续分析ForkJoinTask

 

转载于:https://www.cnblogs.com/wei-zw/p/8797732.html

ForkJoinPool 学习示例相关推荐

  1. python 量化交易_Python量化交易,tushare与talib学习示例演示,双均线(DMA)买卖策略...

    本篇文章为tushare与talib的学习示例,通过双均线策略演示如何使用talib与tushare.下面我们对代码进行详细解析. 引入3个包,分别是talib,tushare和pandas impo ...

  2. Java反射08 : 成员方法Method学习示例

    超级通道: Java泛型学习系列-绪论 java.lang.reflect.Method类提供了用于获取和操作成员方法的静态方法. 1.通过Method可以做什么 通过Method可以做以下事情: 如 ...

  3. python软件代码示例-Python学习示例源码

    函数和函数式编程 函数定义: 函数调用: 过程定义: 过程调用: 面向过程的编程方法: """面向对象-----类------class 面向过程-----过程---- ...

  4. PyG图神经网络框架学习--示例介绍

    实例介绍 通过自带的示例介绍并学习PyG.主要从以下4各方面: 图数据处理 通用基准数据集 Mini-batches 数据转换 图学习方法 图数据处理 图用于对对象(节点)之前的关系(边)进行建模.P ...

  5. 【Flutter】Flutter Gallery 官方示例简介 ( 学习示例 | 邮件应用 | 零售应用 | 理财应用 | 旅行应用 | 新闻应用 | 自适应布局应用 )

    文章目录 一.Reply 邮件应用 二.Shrine 零售应用 三.Rally 理财应用 四.Crane 旅行应用 五.Fortnightly 新闻应用 六.Starter 自适应布局应用 Flutt ...

  6. html 3d转换动画,开源项目:CSS 3D转换和动画学习示例教程

    下面介绍的开源项目,是CSS在动画/3D变换方面的一些应用,非常酷的效果,全部由CSS3来实现. 在这里JavaScript仅作为动画控制来使用,JS并不控制UI界面的具体呈现,切换动画.3D效果仅需 ...

  7. Java反射09 : 参数Parameter学习示例

    超级通道: Java泛型学习系列-绪论 java.lang.reflect.Parameter类提供了用于获取和操作构造器的静态方法. 1.通过Parameter可以做什么 通过Parameter可以 ...

  8. Python_Example_ Data Structures and Algorithm Analysis 学习/示例

    Author: 楚格 2018-11-19   19:05:11 IDE: Pycharm2018.02   Python 3.7 KeyWord :  Data Structures and Alg ...

  9. c语言五子棋蒙特卡洛,五子棋对弈——MCTS学习(示例代码)

    初识AlphaZero AlphaZero能够基于强化学习实现较高技巧的棋类博弈,我看过nb网友实现的基于MCTS的五子棋模型后,惊叹不已!特此记录一下其中训练的一些方法和技巧. MCTS MCTS是 ...

最新文章

  1. elasticsearch系列五:搜索详解(查询建议介绍、Suggester 介绍)
  2. jvm虚拟机_一文入门jvm虚拟机
  3. C / C++ const 的区别和使用
  4. CentOS 7.0 yum安装Apache、PHP和MySQL
  5. RocketMQ消息轨迹-设计篇
  6. php 调用python 脚本
  7. tinymce vue 部分工具不显示_工具栏图标未在tinymce(4.0.1)文本编辑器中显示
  8. java tcp 线程_java 网络协议(一)Tcp多线程服务器端编程
  9. php验证码只有图片没有文字_有没有免费好用的图片文字识别工具?在线就能使用超准确...
  10. UIPageViewController用法
  11. git管理工具使用-本地通过git命令拉取项目
  12. 如何理解T检验和P值
  13. 宝塔面板建立站点无法打开网页解决办法
  14. 阿里面试官:你知道Dubbo的服务暴露机制么?
  15. 百度地图(HTML5新特性)-全面详解(学习总结---从入门到深化)
  16. 主板上还剩啥?CPU整合GPU/北桥/南桥
  17. c++开源协程库libgo介绍及使用
  18. ETHEOS开发资源及工具集合(完整汇总版)
  19. 小米域名拦截检测API接口
  20. Diversitynbsp;order,nbsp;分级阶数

热门文章

  1. docker php 乱码,如何解决docker安装zabbix5.0界面乱码
  2. seo vue 动态路由_基于vue.jsvue-router的动态更新TDK(SEO优化)
  3. html表格全屏显示,tableView滑动全屏显示
  4. java图片上传被旋转,在其他大牛那看到的java手机图片上传旋转问题的解决方法...
  5. php session和cookie区别,php中session和cookie的区别是什么?
  6. php设置上传文件大小限制_php修改上传文件大小限制实例详解
  7. 数组循环简单打印输出
  8. mysql中nchar_浅谈SQL Server、MySQL中char,varchar,nchar,nvarchar区别
  9. Java应用服务器Tomcat
  10. 推荐系统(2)-协同过滤1-UserCF、ItemCF