ForkJoin是Java7提供的原生多线程并行处理框架,其基本思想是将大任务分割成小任务,最后将小任务聚合起来得到结果。fork是分解的意思, join是收集的意思. 它非常类似于HADOOP提供的MapReduce框架,只是MapReduce的任务可以针对集群内的所有计算节点,可以充分利用集群的能力完成计算任务。ForkJoin更加类似于单机版的MapReduce。

在fork/join框架中,若某个子问题由于等待另一个子问题的完成而无法继续执行。那么处理该子问题的线程会主动寻找其他尚未运行完成的子问题来执行。这种方式减少了线程的等待时间,提高了性能。子问题中应该避免使用synchronized关键词或其他方式方式的同步。也不应该是一阻塞IO或过多的访问共享变量。在理想情况下,每个子问题的实现中都应该只进行CPU相关的计算,并且只适用每个问题的内部对象。唯一的同步应该只发生在子问题和创建它的父问题之间。

Fork/Join使用两个类完成以上两件事情:

 
· ForkJoinTask: 我们要使用ForkJoin框架,必须首先创建一个ForkJoin任务。它提供在任务中执行fork()和join的操作机制,ForkJoinTask实现了Future接口,可以按照Future接口的方式来使用。在ForkJoinTask类中之重要的两个方法fork和join。fork方法用以一部方式启动任务的执行,join方法则等待任务完成并返回指向结果。在创建自己的任务是,最好不要直接继承自ForkJoinTask类,而要继承自ForkJoinTask类的子类RecurisiveTask或RecurisiveAction类
    . RecursiveAction,用于没有返回结果的任务
. RecursiveTask,用于有返回值的任务

源码推荐查询 jdk8的

· ForkJoinPool:task要通过ForkJoinPool来执行,分割的子任务也会添加到当前工作线程的双端队列中,进入队列的头部。当一个工作线程中没有任务时,会从其他工作线程的队列尾部获取一个任务。

2个构造方法

ForkJoinPool(int parallelism)  创建一个包含parallelism个并行线程的ForkJoinPool。

ForkJoinPool()  以Runtime.availableProcessors()方法的返回值作为parallelism参数来创建ForkJoinPool。

3种方式启动

异步执行          execute(ForkJoinTask)         ForkJoinTask.fork
等待获取结果   invoke(ForkJoinTask)      ForkJoinTask.invoke
执行,获取Future submit(ForkJoinTask)       ForkJoinTask.fork(ForkJoinTask are Futures)

异常处理:

ForkJoinTask在执行的时候可能会抛出异常,但是没办法在主线程里直接捕获异常,所以ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException方法获取异常.

getException方法返回Throwable对象,如果任务被取消了则返回CancellationException。如果任务没有完成或者没有抛出异常则返回null。

if(task.isCompletedAbnormally()) {
System.out.println(task.getException());
}

然后, 代码展示

import java.util.concurrent.ForkJoinPool
import java.util.concurrent.ForkJoinTask
import java.util.concurrent.RecursiveTask
/**
* fork
* 对一个大数组进行并行求和的RecursiveTask
*
* 大任务可以拆成小任务,小任务还可以继续拆成更小的任务,最后把任务的结果汇总合并,得到最终结果,这种模型就是Fork/Join模型。
Java7引入了Fork/Join框架,我们通过RecursiveTask这个类就可以方便地实现Fork/Join模式。
* Created by wenbronk on 2017/7/13.
*/
class ForkJoinTest extends RecursiveTask<Long> { static final int THRESHOLD =
long[] array
int start
int end ForkJoinTest(long[] array, int start, int end) {
this.start = start
this.end = end
this.array = array
}
@Override
protected Long compute() { if (end - start < THRESHOLD) {
long sum =
for (int i = start; i < end; i++) {
sum += array[i]
}
try {
Thread.sleep()
} catch (Exception e) {
e.printStackTrace()
}
println String.format('compute %d %d = %d', start, end, sum)
} // 对于大任务, 分多线程执行
int middle = (end + start) /
println String.format('split %d %d => %d %d, %d %d', start, end, start, middle, middle, end) def subtask1 = new ForkJoinTest(this.array, start, middle);
def subtask2 = new ForkJoinTest(this.array, middle, end);
invokeAll(subtask1, subtask2) Long subresult1 = subtask1.join()
Long subresult2 = subtask2.join() Long result = subresult1 + subresult2 System.out.println("result = " + subresult1 + " + " + subresult2 + " ==> " + result);
return result
} public static void main(String[] args) throws Exception {
// 创建随机数组成的数组:
long[] array = new long[];
// fillRandom(array);
// fork/join task:
ForkJoinPool fjp = new ForkJoinPool(); // 最大并发数4
ForkJoinTask<Long> task = new ForkJoinTest(array, , array.length);
long startTime = System.currentTimeMillis();
Long result = fjp.invoke(task);
long endTime = System.currentTimeMillis();
System.out.println("Fork/join sum: " + result + " in " + (endTime - startTime) + " ms.");
}
}

java代码的实现

package com.wenbronk.test;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask; /**
* forkjoin的简单易用
* Created by wenbronk on 2017/7/26.
*/
public class CountTask extends RecursiveTask<Integer>{
private volatile static int count = ;
private int start;
private int end; public CountTask(int start, int end) {
this.start = start;
this.end = end;
} public static final int threadhold = ; @Override
protected Integer compute() {
int sum = ;
System.out.println("开启了一条线程单独干: " + count++);
// 如果任务足够小, 就直接执行
boolean canCompute = (end - start) <= threadhold;
if (canCompute) {
for (int i = start; i <= end; i++) {
sum += i;
}
}else {
//任务大于阈值, 分裂为2个任务
int middle = (start + end) / ;
CountTask countTask1 = new CountTask(start, middle);
CountTask countTask2 = new CountTask(middle + , end); // 开启线程
// countTask1.fork();
// countTask2.fork();
invokeAll(countTask1, countTask2); Integer join1 = countTask1.join();
Integer join2 = countTask2.join(); // 结果合并
sum = join1 + join2;
}
return sum;
} // 测试
public static void main(String[] args) throws ExecutionException, InterruptedException {
ForkJoinPool forkJoinPool = new ForkJoinPool(); CountTask countTask = new CountTask(, );
ForkJoinTask<Integer> result = forkJoinPool.submit(countTask);
System.out.println(result.get());
}
}

java-forkjoin框架的使用的更多相关文章

  1. java fork-join框架应用和分析

    http://shmilyaw-hotmail-com.iteye.com/blog/1897636 java fork-join框架应用和分析 博客分类: concurrency multithre ...

  2. JAVA并行框架学习之ForkJoin

    当硬件处理能力不能按照摩尔定律垂直发展的时候,选择了水平发展,多核处理器已经广泛应用.未来随着技术的进一步发展,可能出现成百上千个处理核心,但现有的程序运行在多核心处理器上并不能得到较大性能的提升,主 ...

  3. Java并发编程原理与实战三十二:ForkJoin框架详解

    1.Fork/Join框架有什么用呢? ------->Fork使用来切分任务,Join是用来汇总结果.举个简单的栗子:任务是1+2+3+...+100这个任务(当然这个任务的结果有好的算法去做 ...

  4. Java并发包线程池之ForkJoinPool即ForkJoin框架(一)

    前言 这是Java并发包提供的最后一个线程池实现,也是最复杂的一个线程池.针对这一部分的代码太复杂,由于目前理解有限,只做简单介绍.通常大家说的Fork/Join框架其实就是指由ForkJoinPoo ...

  5. ForkJoin框架

    1. 什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过 ...

  6. Java7 Fork-Join 框架:任务切分,并行处理

    概要 现代的计算机已经向多CPU方向发展,即使是普通的PC,甚至现在的智能手机.多核处理器已被广泛应用.在未来,处理器的核心数将会发展的越来越多.虽然硬件上的多核CPU已经十分成熟,但是很多应用程序并 ...

  7. JUC组件扩展(二)-JAVA并行框架Fork/Join(三):在任务中抛出异常

    在java当中,异常一共分为两种.一种是运行时异常,一种是非运行是异常. 非运行时异常:这些异常必须在方法上通过throws子句抛出.或者在方法体内进行try{…}catch{…}来捕获异常. 运行时 ...

  8. Java--8--新特性--串并行流与ForkJoin框架

    并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流.穿行流则相反,并行流的底层其实就是ForkJoin框架的一个实现. 那么先了解一下ForkJoin框架吧. Fork/Join ...

  9. Java集合框架List,Map,Set等全面介绍

    Java集合框架的基本接口/类层次结构: java.util.Collection [I]+--java.util.List [I]   +--java.util.ArrayList [C]   +- ...

  10. Java集合框架练习-计算表达式的值

    最近在看<算法>这本书,正好看到一个计算表达式的问题,于是就打算写一下,也正好熟悉一下Java集合框架的使用,大致测试了一下,没啥问题. import java.util.*; /* * ...

随机推荐

  1. 微信公众平台如何与Web App结合?

    Web App简而言之就是为移动平台而优化的网页,它可以表现得和原生应用一样,并且克服了原生应用一些固有的缺点.一般而言Web App最大的入口是浏览器,但现在微信公众平台作为新兴的平台,结合其内置浏 ...

  2. DBCC--常用跟踪标记

    使用DBCC TRACEON 和DBCC TRACEOFF来打开和关闭跟踪标记 使用DBCC TRACESTATUS来查看所有打开的跟踪标记 --260:打印关于扩展存储过程动态链接库的版本信息 -- ...

  3. 服务端JSON内容中有富文本时

    问题背景 由于数据中存在复杂的富文本,包含各种引号和特殊字符,导致后端和前端通过JSON格式进行数据交互引发前端JSON解析出错. 解决方案 后端将富文本内容 ConvertToBase64Strin ...

  4. C# null,string.Empty,"",DBNull 的区别

    [null] null 在C# 中是一个关键字,表示不引用任何对象的空引用的文字值. null 是引用类型变量的默认值. 普通值类型不能为 null. null 在 VS 中定位不出来具体是怎么定义的 ...

  5. C#构造方法(函数)

    一.概括 1.通常创建一个对象的方法如图: 通过  Student tom = new Student(); 创建tom对象,这种创建实例的形式被称为构造方法. 简述:用来初始化对象的,为类的成员赋值 ...

  6. PropertyPlaceHolderConfigurer中的location是不是用错了?

    本文由作者张远道授权网易云社区发布. spring中常用PropertyPlaceHolderConfigurer来读取properties配置文件的配置信息.常用的配置方式有两种,一种是使用loca ...

  7. strlen()与mb_strlen()的区别

    1,strlen()是php的内置函数,可以在php中直接调用:mb_strlen()是php的扩展,需要配置php.ini,以开启mb_strlen()扩展.在php.ini中加载了php_mbst ...

  8. Tomcat启动内存设置

    Tomcat启动内存设置 Tomcat的启动分为startupo.bat启动和注册为windows服务的启动,下面一一说明. 1.startup.bat启动 在tomcat_home/bin目录下找到 ...

  9. 在阿里云服务器中安装配置mysql数据库完整教程

    阿里云ECS服务器CentOS7上安装MySql服务 (可选)1.确保服务器系统处于最新状态 [root@localhost ~]# yum -y update如果显示以下内容说明已经更新完成 Rep ...

  10. leetcode-165-比较版本号

    题目描述: 比较两个版本号 version1 和 version2.如果 version1 > version2 返回 1,如果 version1 < version2 返回 -1, 除此 ...