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. UINavigationController 、navigationBar 、 UINavigationItem、UIBarButtonItem之间的关系

  2. 《剑指offer》 二进制中1的个数

    本题来自<剑指offer> 二进制中1的个数 题目: 输入一个整数,输出该数二进制表示中1的个数.其中负数用补码表示. 思路: 两种思路: 第一种:对n进行左移,检测最后一位是否为1,但考 ...

  3. kali linux宿主机和虚拟机互访实现方案

    1.攻防模拟中,将DVWA安装到自己的宿主机中,在kali Linux中通过sqlmap和其他工具启动嗅探攻击,需要配置网络.虚拟机采用桥接方式,并复制Mac地址状况. 2.查看各自系统下的IP地址. ...

  4. java方法重载和重写

    1.java的方法重载和重写,表示两种不同的类型.this关键字,出现在类的构造方法中,代表使用该构造方法所创建的对象.,this可以出现在实例方法中核构造方法中.但是不能出现在类方法中.实例方法只能 ...

  5. jmeter IP欺骗功能

    使用过loadrunner的同学,应该都了解有个IP欺骗功能,jmeter遇到类似需求怎样实现呢? 环境:windows7,jdk1.8,jmeter3.1 使用IP欺骗功能前提是本地有多个可用IP, ...

  6. jquery实现全选 反选 取消

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. .netcore读取配置文件

    setting.json { "compilerOptions": { "noImplicitAny": false, "noEmitOnError& ...

  8. SQL Server 对字符进行排序(数字类的字符)

    使用的是SQLserver数据库测试,其他数据库类似. 默认排序是按ID进行排序的 select stu_id ,stu_name from student order by stu_id. 现在需要 ...

  9. SqlBulkCopy批量插入数据神器

    1.简单例子 class Program { static void Main(string[] args) { Stopwatch sw = new Stopwatch(); DataTable d ...

  10. 【SpringBoot】常用注解

    @EnableAutoConfiguration 启动自动装载:使用了这个注解之后,所有引入的jar的starters都会被自动注入.这个类的设计就是为starter工作的. @RestControl ...