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. Confluence 6 XML 备份恢复失败的问题解决

    XML 站点备份仅仅针对新数据库恢复的时候是必要的. Upgrading Confluence,Setting up a test server 或者 Production Backup Strate ...

  2. openmp

    https://blog.csdn.net/fuwenyan/article/details/79500765a https://www.cnblogs.com/yangyangcv/archive/ ...

  3. Java的动手动脑(五)

    日期:2018.11.1 星期四 博客期:021 Part1: 运行代码 class Grandparent { public Grandparent() { System.out.println(& ...

  4. redis 单实例安装

    单实例安装 近些年,由于内存技术的提升.造价的下降,越来越多企业的服务器内存已增加到几百G.这样的内存容量给了内存数据库一个良好的发展环境. 而使用Redis是内存数据库的一股清流,渐有洪大之势.下面 ...

  5. 51 Nod 1079 中国剩余定理(孙子定理)NOTE:互质情况

    1079 中国剩余定理 一个正整数K,给出K Mod 一些质数的结果,求符合条件的最小的K.例如,K % 2 = 1, K % 3 = 2, K % 5 = 3.符合条件的最小的K = 23. 收起 ...

  6. 小米8如何root

    现身说法,实测有效,也踩坑很多. 0. 准备手机.数据线.windows系统的电脑.小米帐号,各一个. 手机需要装上sim卡:电脑需要能上网.最好是有wifi的环境,用来下载安装包. 注意提前备份数据 ...

  7. ES优化总结

    ES优化总结(特别是在bulk大量数据到ES的时候) https://blog.csdn.net/chenxun_2010/article/details/78602795 将 ELASTICSEAR ...

  8. KnockoutJs学习笔记(三)

    之前的文章主要针对的是单一的observable(即便是observableArray也是一种observable),而文档Using computed observables则主要是针对ko.com ...

  9. mysql的下载与安装

    官网 下载 https://www.mysql.com/ 依次点击:downloads>community>mysql community server,如图所示   image.png ...

  10. update + join 多表操作

    UPDATE vtiger_notificationcf as a INNER JOIN vtiger_crmentity as b ON a.notificationid = b.crmid SET ...