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 重新获得站点备份文件

    Confluence 将会创建备份,同时压缩 XML 文件后存储熬你的 <home-directory>/backups> 目录中.你需要自己访问你安装的 Confluence 服务 ...

  2. Confluence 6 服务器的许可证信息

    Confluence 6 服务器的许可证信息. https://www.cwiki.us/display/CONFLUENCEWIKI/Managing+your+Confluence+License

  3. eclipse c++11 cmake gnuradio

    承接之前的脚本.修改一下这个脚本的代码就可以让eclipse使用C++11了 #!/bin/sh echo "creat_debug for sdk" echo "mkd ...

  4. cf1132G 线段树解分区间LIS(一种全新的线段树解LIS思路)+单调栈

    /* 给定n个数的数列,要求枚举长为k的区间,求出每个区间的最长上升子序列长度 首先考虑给定n个数的数列的LIS求法:从左往右枚举第i点作为最大点的贡献, 那么往左找到第一个比a[i]大的数,设这个数 ...

  5. CF979E

    非常好的dp,非常考dp的能力 很显然是个计数问题,那么很显然要么是排列组合,要么是递推,这道题很显然递推的面更大一些. 那么我们来设计一下状态: 设状态f[i][j][k][p]表示目前到了第i个点 ...

  6. java设置字符串编码、转码

    Unicode(统一码.万国码.单一码)是计算机科学领域里的一项业界标准,包括字符集.编码方案等.Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一 ...

  7. 安装Mycat 曾经踩的那些坑

    1. INFO | jvm | ----/--/-- --:--:-- | Caused by: io.mycat.config.util.ConfigException: schema TEST d ...

  8. 步步为营-87-imageAreaSelect插件使用(图片剪切)

    1 引用文件 jquery.imgareaselect.min.cs imgareaselect-default.js 2 代码 <%@ Page Language="C#" ...

  9. IDEA窗口重置

  10. install memcached for ubuntu

    Memcached安装 1.先下载安装libevent 安装 libevent# tar zxvf libevent-1.4.9-stable.tar.gz# cd libevent-1.4.9-st ...