jdk1.7中提供了Fork/Join并行执行任务框架,主要作用就是把大任务分割成若干个小任务,再对每个小任务得到的结果进行汇总。

正常情况下,一些小任务我们可以使用单线程递归来实现,但是如果要想充分利用CPU资源,就需要把一个任务分成若干个小任务,并行执行了,这就是分治编程。

在JDK中,并行执行框架Fork-Join使用了“工作窃取(work-stealing)”算法。

JDK1.7中实现分治编程思路:

  使用 ForkJoinPool 类提供了一个任务池。

  具体执行任务需要靠 ForkJoinTask 类,而 ForkJoinTask 是抽象类,故使用该类的3个子类 CountedCompleter、RecursiveAction、RecursiveTask 来实现具体的功能。

  其中,RecursiveAction 执行的任务具有无返回值,且仅执行一次;RecursiveTask 执行任务可以通过方法 join() 或者 get() 取得方法返回值。

  补充, join() 和 get() 的区别:两个方法都可以获得计算后的结果值,区别是在子任务报异常时,get() 的异常可以在main主线程中进行捕获;而 join() 的异常会直接抛出。

看例子(求和:1+2+3+...+9999+10000):

package com.cd.thread;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask; public class ForkJoinTest {
public static void main(String[] args) {
final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("start-time:" + sf.format(new Date()));
addTest(); // for循环
System.out.println("end-time:" + sf.format(new Date()));
System.out.println("start-time:" + sf.format(new Date()));
forkJoinTest();// 分治求和
System.out.println("end-time:" + sf.format(new Date()));
} private static void addTest() {
int beginNum = 1, endNum = 10000, val = 0;
for (int i = beginNum; i <= endNum; i++) {
val += i;
}
System.out.println("for循环结果:" + val);
} public static void forkJoinTest() {
MyRecursiveTask task = new MyRecursiveTask(1, 10000);
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Integer> fjTask = pool.submit(task);
try {
System.out.println("分治求和结果:" + fjTask.get());
} catch (Exception e) {
e.printStackTrace();
}
} private static class MyRecursiveTask extends RecursiveTask<Integer> { private Integer beginNum; private Integer endNum; private MyRecursiveTask(Integer beginNum, Integer endNum) {
this.beginNum = beginNum;
this.endNum = endNum;
} @Override
protected Integer compute() {
if ((endNum - beginNum) > 500) {
int middleNum = (endNum + beginNum) / 2;
MyRecursiveTask task1 = new MyRecursiveTask(beginNum, middleNum);
MyRecursiveTask task2 = new MyRecursiveTask(middleNum + 1, endNum);
this.invokeAll(task1, task2);
// return task1.join() + task2.join();
Integer num1 = 0, num2 = 0;
try {
num1 = task1.get();
num2 = task2.get();
} catch (Exception e) {
e.printStackTrace();
}
return num1 + num2;
} else {
Integer val = 0;
for (int i = beginNum; i <= endNum; i++) {
val += i;
}
return val;
}
} } }

从结果看,分治编程不一定会比单线程快,所以在用分治编程的时候,需要一定的测试才行。

而分治编程也有运用的领域,比如遍历一个目录及其子目录,处理一个树形结构算法问题。

在写代码的时候,会发现分治的代码看起来像递归,但是其实它们是并行执行的。

关于 ForkJoinPool 的 api,建议用到的时候,去看文档吧,看文档也是一种能力,也是一种技巧。

【java并发核心八】Fork-Join分治编程的更多相关文章

  1. 【java并发系列】Fork/Join任务(转)

    原文链接 当我们需要执行大量的小任务时,有经验的Java开发人员都会采用线程池来高效执行这些小任务.然而,有一种任务,例如,对超过1000万个元素的数组进行排序,这种任务本身可以并发执行,但如何拆解成 ...

  2. JAVA并发工具类---------------(Fork/Join)

    Fork/Join 分而治之 将一个大任务分成数个小任务执行,然后将这些小人物执行后的结果进行join汇总: (假设:你要计算1到1000的总和,你可以把它分成1-100,101-200,...... ...

  3. 【Java并发核心三】CountDownLatch、CyclicBarrier及Phaser

    个人感觉,看书学习还是需要“不求甚解”,因为一旦太过于计较小的得失,就容易钻牛角尖,学习进度也慢.我们完全可以先学一个大概,等到真正用到的时候再把那些细节丰富起来,就更有针对性. 所以,针对java并 ...

  4. 并发编程之Fork/Join

    并发与并行 并发:多个进程交替执行. 并行:多个进程同时进行,不存在线程的上下文切换. 并发与并行的目的都是使CPU的利用率达到最大.Fork/Join就是为了尽可能提高硬件的使用率而应运而生的. 计 ...

  5. JAVA并行框架:Fork/Join

    一.背景 虽然目前处理器核心数已经发展到很大数目,但是按任务并发处理并不能完全充分的利用处理器资源,因为一般的应用程序没有那么多的并发处理任务.基于这种现状,考虑把一个任务拆分成多个单元,每个单元分别 ...

  6. 【java并发核心一】Semaphore 的使用思路

    最近在看一本书<Java并发编程 核心方法与框架>,打算一边学习一边把学习的经验记下来,所粘贴的代码都是我运行过的,大家一起学习,欢迎吐槽. 估计也没多少人看我的博客,哈哈,那么我还是会记 ...

  7. Java并发(八)计算线程池最佳线程数

    目录 一.理论分析 二.实际应用 为了加快程序处理速度,我们会将问题分解成若干个并发执行的任务.并且创建线程池,将任务委派给线程池中的线程,以便使它们可以并发地执行.在高并发的情况下采用线程池,可以有 ...

  8. java成神之——Fork/Join基本使用

    Fork/Join 大任务分小任务,小任务结果合并 ForkJoinPool pool = new ForkJoinPool(); RecursiveTask<Integer> task1 ...

  9. Java并发(八):AbstractQueuedSynchronizer

    先做总结: 1.AbstractQueuedSynchronizer是什么? AbstractQueuedSynchronizer(AQS)这个抽象类,是Java并发包 java.util.concu ...

随机推荐

  1. vue之自行实现派发与广播-dispatch与broadcast

    要解决的问题 主要针对组件之间的跨级通信 为什么要自己实现dispatch与broadcast? 因为在做独立组件开发或库时,最好是不依赖第三方库 为什么不使用provide与inject? 因为它的 ...

  2. ionic2 子页面隐藏去掉底部tabs导航,子页面全占满显示方法(至今为止发现的最靠谱的方法)

    项目中遇到 tabs 字页面 可以用以下代码隐藏的方式: imports: [ BrowserModule, // IonicModule.forRoot(MyApp), HttpModule, Io ...

  3. ob_start用法详解

    用PHP的ob_start(); 一. 相关函数简介:1.Flush:刷新缓冲区的内容,输出.函数格式:flush()说明:这个函数经常使用,效率很高.2.ob_start :打开输出缓冲区函数格式: ...

  4. 深入分析Zookeeper的实现原理

    zookeeper 的由来 分布式系统的很多难题,都是由于缺少协调机制造成的.在分布式协调这块做得比较好的,有 Google 的 Chubby 以及 Apache 的 Zookeeper.Google ...

  5. CentOS下将Python的版本升级为3.x

    本文主要介绍在Linux(CentOS)下将Python的版本升级为3.x的方法 众所周知,在2020年python官方将不再支持2.7版本的python,所以使用3.x版本的python是必要的,但 ...

  6. Mac下Java JDK的下载安装和配置

    一.下载安装 打开一个搜索引擎,输入JDK,找到Java JDK 如图:  点击打开,同意协议开始下载如图: 下载好以后,安装即可. 安装成功以后,进入根目录,可以找到JDK安装的位置: 资源库——& ...

  7. matlab转c++代码实现(主要包含C++ std::vector,std::pair学习,包含数组与常数相乘,数组相加减,将数组拉成一维向量,图片的读入等内容)

    MATLAB部分: xmap = repmat( linspace( -regionW/2, regionW/2, regionW), regionH, 1 );%linspace [x1,x2,N] ...

  8. STL用法大全

    1.    概述 泛型编程思想最早缘于A.Stepanov提出的部分算法可独立于数据结构的论断.20世纪90年代初A.Stepanov和Meng Lee根据泛型编程的理论用C++共同编写了STL.但直 ...

  9. PHP中self和this的用法区别

    PHP支持类和面向对象结构,PHP的类的静态函数和变量不与任何特定类的实例相关联(换句话说,一个对象).请看:类与对象的区别. 相反,静态函数和变量与类定义本身相关联.换言之,一个类的所有实例都共享相 ...

  10. 一脸懵逼学习Storm的搭建--(一个开源的分布式实时计算系统)

    Storm的官方网址:http://storm.apache.org/index.html :集群部署的基本流程(基本套路): 集群部署的流程:下载安装包.解压安装包.修改配置文件.分发安装包.启动集 ...