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. opencpu

    前端通过它调用后端的R语言,对R函数进行一个封装. 网址:https://github.com/jeroenooms/opencpu.js 使用的是opencpu-0.5.js,对它进行了修改. 1. ...

  2. web.xml中Filter,Listener,Servlet的区别

    一.Servlet Servlet是基本的服务端程序,他来自接口Servlet,接口中有方法service.而Servlet的一个重要实现类,则是tomcat服务器的核心,那就是HttpServlet ...

  3. System.Windows.Freezable 在未被引用的程序集中定义

    System.Windows.Freezable 在未被引用的程序集中定义 解决方法 添加windowsbase.dll 引用

  4. Jenkins中执行docker命令报错

    Cannot connect to the Docker daemon. Is the docker daemon running on this host?   在配置Jenkins从Gitlab自 ...

  5. 简易Python语句获取本机ip地址

    import os, socket def public_ip(): try: s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.conne ...

  6. spring boot 使用 HandlerInterceptor

    # 背景 在实际项目中,接口出于安全考虑,都会有验签的计算.目前接触的项目来看基本都是时间戳+干扰因子 然后md5计算的方式.现在学习,写一个简单demo, 其实如果不引入拦截器的话,验签计算全部在c ...

  7. C#多线程编程系列(四)- 使用线程池

    目录 1.1 简介 1.2 在线程池中调用委托 1.3 向线程池中放入异步操作 1.4 线程池与并行度 1.5 实现一个取消选项 1.6 在线程池中使用等待事件处理器及超时 1.7 使用计时器 1.8 ...

  8. R语言和RStudio的一些用法,常用命令等

    控制台: Up/down 回忆之前的命令 Ctrl+Up 回顾命令列表(可先输入前缀进行查找) 焦点: ctrl+ 移动焦点到source编辑器 ctrl+ 移动焦点到console ctrl+L 清 ...

  9. STL在数组算法的使用

    find(a:起始位置 , b: 终止位置 , c: 要查找的内容)      ------>查找寻找内容的位置 count(a:起始位置 , b: 终止位置 , c: 要查找的内容)   -- ...

  10. 《Python绝技:运用Python成为顶级黑客》 用Python进行无线网络攻击

    本章大部分代码都是实现了但是缺乏相应的应用环境,想具体测试的可以直接找到对应的环境或者自行修改脚本以适应生活常用的环境. 1.搭建无线网络攻击环境: 用Scapy测试无线网卡的嗅探功能: 插入无线网卡 ...