介绍:

  a . Fork/Join为JKD1.7引入,适用于对大量数据进行拆分成多个小任务进行计算的框架,最后把所有小任务的结果汇总合并得到最终的结果

  b . 相关类

public abstract class RecursiveTask<V> extends ForkJoinTask<V>;
public abstract class RecursiveAction extends ForkJoinTask<Void>;

  c . 其中RecursiveTask在执行有返回值的任务时使用,RecursiveAction在执行没有返回值的任务时使用

实例代码:

  ForkJoin有参无返回值

  参数:map

public class UpdatePlayersTotalTimeTask extends RecursiveAction {

    private static final int THRESHOLD_NUM = 30;//定义任务的切分阀值
private Map<String,String> players;
private PlayerTotalTimeService playerTotalTimeService;
private MongoDao mongoDao; public UpdatePlayersTotalTimeTask(Map<String,String> players, MongoDao mongoDao) {
this.players = players;
this.mongoDao = mongoDao;
} @Override
protected void compute() {
boolean canCompute = players.size() <= THRESHOLD_NUM;
if (canCompute) {
playerTotalTimeService = new PlayerTotalTimeService();
playerTotalTimeService.updatePlayersTotalTime(players, mongoDao);
} else {
       // 将任务一份为二
int middle = players.size() / 2; int i = 0;
Map<String, String> leftMap = new HashMap<>();
Map<String, String> rightMap = new HashMap<>(); for (Map.Entry<String, String> entry : players.entrySet()) {
if (i < middle) {
leftMap.put(entry.getKey(), entry.getValue());
} else {
rightMap.put(entry.getKey(), entry.getValue());
}
i++;
} UpdatePlayersTotalTimeTask leftTask = new UpdatePlayersTotalTimeTask(leftMap, mongoDao);
UpdatePlayersTotalTimeTask rightTask = new UpdatePlayersTotalTimeTask(rightMap, mongoDao); // 执行子任务
leftTask.fork();
rightTask.fork();
}
}

  //调用测试
public static void main(String[] args) throws InterruptedException {
// 创建包含Runtime.getRuntime().availableProcessors()返回值作为个数的并行线程的ForkJoinPool
ForkJoinPool forkjoinPool = new ForkJoinPool(); Map<String, String> map = new HashMap<>();
     map.put("key1","value1");
MongoDao mongoDao = new MongoDaoImpl();
//生成一个计算任务
UpdatePlayersTotalTimeTask task = new UpdatePlayersTotalTimeTask(map, mongoDao);
// 提交可分解的PrintTask任务
forkjoinPool.excute(task);
forkjoinPool.awaitTermination(2, TimeUnit.SECONDS);//阻塞当前线程直到 ForkJoinPool 中所有的任务都执行结束
// 关闭线程池
forkjoinPool.shutdown();
} }

  ForkJoin有参有返回值        (继承RecursiveTask<T>类)

  参数:set<String>   返回值:map<String,String>

 public class CalcRoomPlayersTotalTimeTask extends RecursiveTask<Map<String,String>> {
private static final int THRESHOLD_NUM = 15;
private Set<String> roomSet;
private PlayerTotalTimeService playerTotalTimeService;
private MongoDao mongoDao; public CalcRoomPlayersTotalTimeTask(Set<String> roomSet, MongoDao mongoDao) {
this.roomSet = roomSet;
this.mongoDao = mongoDao;
} @Override
protected Map<String,String> compute() { playerTotalTimeService = new PlayerTotalTimeService();
//如果任务足够小就计算任务
boolean canCompute = roomSet.size() <= THRESHOLD_NUM;
if (canCompute) { Map<String,String> playersResult = new HashMap<>(); playersResult = playerTotalTimeService.calcRoomPlayersTotalTime(roomSet, mongoDao); return playersResult;
} else {
// 如果任务大于阈值,就分裂成两个子任务计算
long middle = roomSet.size() / 2;
Set<String> leftSet = new HashSet<>();
Set<String> rightSet = new HashSet<>(); long i = 0;
for (String room : roomSet) {
if (i < middle) {
leftSet.add(room);
} else {
rightSet.add(room);
}
i++;
} CalcRoomPlayersTotalTimeTask leftTask = new CalcRoomPlayersTotalTimeTask(leftSet,mongoDao);
CalcRoomPlayersTotalTimeTask rightTask = new CalcRoomPlayersTotalTimeTask(rightSet,mongoDao); // 执行子任务
invokeAll(leftTask,rightTask); HashMap<String,String> result = new HashMap<>(); Map<String,String> leftResult = leftTask.join();
Map<String,String> rightResult = rightTask.join(); result.putAll(leftResult); for (Map.Entry<String, String> entry : rightResult.entrySet()) {
boolean contains = result.containsKey(entry.getKey());
if(contains){
String playerTotalTimeStr = entry.getValue();
Long playerTotalTimeLong = playerTotalTimeService.timeStringToLong(result.get(entry.getKey())) + playerTotalTimeService.timeStringToLong(playerTotalTimeStr);
playerTotalTimeStr = playerTotalTimeService.timeLongToString(playerTotalTimeLong);
result.put(entry.getKey(),playerTotalTimeStr);
}else {
result.put(entry.getKey(),entry.getValue());
}
} return result;
}
} public static void main(String[] args) throws InterruptedException {
// 创建包含Runtime.getRuntime().availableProcessors()返回值作为个数的并行线程的ForkJoinPool
ForkJoinPool forkjoinPool = new ForkJoinPool(); Set<String> roomSet = new HashSet<>();
Map<String,String> map = new HashMap<String,String>();
MongoDao mongoDao = new MongoDaoImpl();
//生成一个计算任务
CalcRoomPlayersTotalTimeTask task = new CalcRoomPlayersTotalTimeTask(roomSet, mongoDao); // 提交可分解的PrintTask任务
       map = forkjoinPool.invoke(task);
forkjoinPool.awaitTermination(2, TimeUnit.SECONDS);//阻塞当前线程直到 ForkJoinPool 中所有的任务都执行结束
// 关闭线程池
forkjoinPool.shutdown();
}
}

说明:

  a .在有大量计算任务时,此框架方法可进行并行计算效率高,以上示例,可以根据具体的业务需求更改属性及相关方法用于匹配自己的业务逻辑

b .JDK1.8后由于加入Stream流的操作,集合框架可以使用Collection<E> default Stream<E> parallelStream()的方法转换成并行流进行计算,此时效果与Fork/Join任务同效

c .ForkJoinPool中的多种方法

 public <T> ForkJoinTask<T> submit(ForkJoinTask<T> task);//等待获取结果
public void execute(ForkJoinTask<?> task);//异步执行
public <T> T invoke(ForkJoinTask<T> task);//执行,获取Future

d .ForkJoinTask在执行的时候可能会抛出异常,但是没办法在主线程里直接捕获异常,所以ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException方法获取异常。getException方             法返回Throwable对象,如果任务被取消了则返回CancellationException。如果任务没有完成或者没有抛出异常则返回null。

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

注:部分内容引自https://segmentfault.com/a/1190000010209196

ForkJoin有参无返回值、有参有返回值实例的更多相关文章

  1. 慕课网-Java入门第一季-7-2 Java 中无参无返回值方法的使用

    来源:http://www.imooc.com/code/1578 如果方法不包含参数,且没有返回值,我们称为无参无返回值的方法. 方法的使用分两步: 第一步,定义方法 例如:下面代码定义了一个方法名 ...

  2. Java 中无参无返回值方法的使用

    如果方法不包含参数,且没有返回值,我们称为无参无返回值的方法. 方法的使用分两步: 第一步,定义方法 例如:下面代码定义了一个方法名为 show ,没有参数,且没有返回值的方法,执行的操作为输出 “ ...

  3. 065 01 Android 零基础入门 01 Java基础语法 08 Java方法 02 带参无返回值方法

    065 01 Android 零基础入门 01 Java基础语法 08 Java方法 03 带参无返回值方法 本文知识点:带参无返回值方法 说明:因为时间紧张,本人写博客过程中只是对知识点的关键步骤进 ...

  4. 063 01 Android 零基础入门 01 Java基础语法 08 Java方法 01 无参无返回值方法

    063 01 Android 零基础入门 01 Java基础语法 08 Java方法 01 无参无返回值方法 本文知识点:无参无返回值方法 无参无返回值方法 案例 为什么使用方法?--方便复杂问题调用 ...

  5. 超全table功能Datatables使用的填坑之旅--2:post 动态传参: 解决: ajax 传参无值问题.

    官网解释与方法:1 当向服务器发出一个ajax请求,Datatables将会把服务器请求到的数据构造成一个数据对象. 2 实际上他是参考jQuery的ajax.data属性来的,他能添加额外的参数传给 ...

  6. Java JDBC调用存储过程:无参、输入带参、输出及输出带参

    Java JDBC调用存储过程:无参.输入带参.输出及输出带参 示例代码: package xzg; import java.sql.CallableStatement; import java.sq ...

  7. python中的无参装饰器和有参装饰器

    python中的无参装饰器和有参装饰器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 装饰器特点: 1>.开放封闭原则,即对扩展是开放的,对修改时封闭的: 2>.装饰器 ...

  8. C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.之前分享过一篇 C#进阶系列——WebApi接口传参不再困惑:传参详解  ...

  9. WebApi接口返回值不困惑:返回值类型详解

    前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学习Webapi的园友们速速动起来,跟着博主一起来学习吧.作为程序猿,我们都知道参数和返回值是编程领域不可分割的两大块,此前分享了 ...

随机推荐

  1. tcpdump网络数据抓包

    tcpdump,就是:dump the traffic on a network,根据使用者的定义对网络上的数据包进行截获的包分析工具. tcpdump可以将网络中传送的数据包的“头”完全截获下来提供 ...

  2. Learning Python 003 缩进

    Python 缩进 Python的代码中不使用{}大括号来来表示一个代码块,而是使用缩进方式.像下面这段代码: # print absolute value of an integer: a = 10 ...

  3. Java堆分析

  4. 第四课4、ROS客户端

    ROS客户端提供一些列库文件用于用户开发.它利用许多ROS概念并使它通过代码可以获取. 下面是ROS程序中的接口 ROSCPP客户端(c++客户端) 首先新建一个包 然后catkin_make一下 在 ...

  5. hdu1068

    #include<stdio.h>#include<string.h>const int MAXN=1000;int map[MAXN][MAXN];int n;int lin ...

  6. idea中java项目增加module后,手动增加xml文件,合并到webapp/WEB-INFO或WEB-INFO(包)

    当手工增加一个module,增加配置文件(如:web.xml)需要合并到文件夹里,要不众多文件在一个src文件夹下,太凌乱. 1. 合并到webapp/WEB-INFO下 a. 首先增加webapp目 ...

  7. hello markdown

    目录 标题 标题1 标题2 标题3 有序列表 无序列表 插入图片 插入链接 粗体.斜体.删除线 引用 表格 代码 目录 新的开始 希望能够坚持下去 cnblogs也支持markdown 之前看了写ma ...

  8. Delphi Runtime Library在哪里?

    Delphi Runtime Library是Delphi的运行时库,里面包含了大部分Delphi库的代码,这些库代码在哪里呢?其实正常安装完Dephi之后,在它的安装目录下面!下面我以我的Delph ...

  9. Educational Codeforces Round 57 (Rated for Div. 2)D(动态规划)

    #include<bits/stdc++.h>using namespace std;char s[100007];long long a[100007];long long dp[100 ...

  10. Mac安装vue

     Mac安装vue 一.安装brew 打开终端运行以下命令: /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com ...