Java7任务并行执行神器:Fork&Join框架
Java7任务并行执行神器:Fork&Join框架
Java技术栈
阅读数:426
<span class="tags-box artic-tag-box">
<span class="label">标签:</span>
<a data-track-click="{"mod":"popu_626","con":"JAVA"}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=JAVA&t=blog" target="_blank">JAVA </a><a data-track-click="{"mod":"popu_626","con":"FORKJOIN"}" class="tag-link" href="http://so.csdn.net/so/search/s.do?q=FORKJOIN&t=blog" target="_blank">FORKJOIN </a>
<span class="article_info_click">更多</span></span>
<div class="tags-box space">
<span class="label">个人分类:</span>
<a class="tag-link" href="https://blog.csdn.net/youanyyou/article/category/695509" target="_blank">Java </a>
</div>
</div>
<div class="operating">
</div>
</div>
</div>
</div>
<article>
<div id="article_content" class="article_content clearfix csdn-tracking-statistics" data-pid="blog" data-mod="popu_307" data-dsm="post">
<div class="article-copyright">
版权声明:转载请注明原文链接,非法转载者将追究其法律责任。 https://blog.csdn.net/youanyyou/article/details/78990280 </div>
<div class="markdown_views">
<!-- flowchart 箭头图标 勿删 -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
<h4 id="forkjoin是什么">Fork/Join是什么?</h4>
Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为大任务结果。其思想和MapReduce的思想非常类似。对于任务的分割,要求各个子任务之间相互独立,能够并行独立地执行任务,互相之间不影响。
Fork/Join的运行流程图如下:

我们可以通过Fork/Join单词字面上的意思去理解这个框架。Fork是叉子分叉的意思,即将大任务分解成并行的小任务,Join是连接结合的意思,即将所有并行的小任务的执行结果汇总起来。

工作窃取算法
ForkJoin采用了工作窃取(work-stealing)算法,若一个工作线程的任务队列为空没有任务执行时,便从其他工作线程中获取任务主动执行。为了实现工作窃取,在工作线程中维护了双端队列,窃取任务线程从队尾获取任务,被窃取任务线程从队头获取任务。这种机制充分利用线程进行并行计算,减少了线程竞争。但是当队列中只存在一个任务了时,两个线程去取反而会造成资源浪费。
工作窃取的运行流程图如下:

Fork/Join核心类
Fork/Join框架主要由子任务、任务调度两部分组成,类层次图如下。
- ForkJoinPool
ForkJoinPool是ForkJoin框架中的任务调度器,和ThreadPoolExecutor一样实现了自己的线程池,提供了三种调度子任务的方法:
- execute:异步执行指定任务,无返回结果;
- invoke、invokeAll:异步执行指定任务,等待完成才返回结果;
submit:异步执行指定任务,并立即返回一个Future对象;
- ForkJoinTask
Fork/Join框架中的实际的执行任务类,有以下两种实现,一般继承这两种实现类即可。
- RecursiveAction:用于无结果返回的子任务;
- RecursiveTask:用于有结果返回的子任务;
Fork/Join框架实战
下面实现一个Fork/Join小例子,从1+2+…10亿,每个任务只能处理1000个数相加,超过1000个的自动分解成小任务并行处理;并展示了通过不使用Fork/Join和使用时的时间损耗对比。
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class ForkJoinTask extends RecursiveTask<Long> {
private static final long MAX = 1000000000L;
private static final long THRESHOLD = 1000L;
private long start;
private long end;
public ForkJoinTask(long start, long end) {
this.start = start;
this.end = end;
}
public static void main(String[] args) {
test();
System.out.println("--------------------");
testForkJoin();
}
private static void test() {
System.out.println("test");
long start = System.currentTimeMillis();
Long sum = 0L;
for (long i = 0L; i <= MAX; i++) {
sum += i;
}
System.out.println(sum);
System.out.println(System.currentTimeMillis() - start + "ms");
}
private static void testForkJoin() {
System.out.println("testForkJoin");
long start = System.currentTimeMillis();
ForkJoinPool forkJoinPool = new ForkJoinPool();
Long sum = forkJoinPool.invoke(new ForkJoinTask(1, MAX));
System.out.println(sum);
System.out.println(System.currentTimeMillis() - start + "ms");
}
@Override
protected Long compute() {
long sum = 0;
if (end - start <= THRESHOLD) {
for (long i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
long mid = (start + end) / 2;
ForkJoinTask task1 = new ForkJoinTask(start, mid);
task1.fork();
ForkJoinTask task2 = new ForkJoinTask(mid + 1, end);
task2.fork();
return task1.join() + task2.join();
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
这里需要计算结果,所以任务继承的是RecursiveTask类。ForkJoinTask需要实现compute方法,在这个方法里首先需要判断任务是否小于等于阈值1000,如果是就直接执行任务。否则分割成两个子任务,每个子任务在调用fork方法时,又会进入compute方法,看看当前子任务是否需要继续分割成孙任务,如果不需要继续分割,则执行当前子任务并返回结果。使用join方法会阻塞并等待子任务执行完并得到其结果。
程序输出:
test
500000000500000000
4992ms
--------------------
testForkJoin
500000000500000000
508ms
- 1
- 2
- 3
- 4
- 5
- 6
- 7
从结果看出,并行的时间损耗明显要少于串行的,这就是并行任务的好处。
尽管如此,在使用Fork/Join时也得注意,不要盲目使用。
- 如果任务拆解的很深,系统内的线程数量堆积,导致系统性能性能严重下降;
- 如果函数的调用栈很深,会导致栈内存溢出;
推荐阅读
分享Java干货,高并发编程,热门技术教程,微服务及分布式技术,架构设计,区块链技术,人工智能,大数据,Java面试题,以及前沿热门资讯等。
<script>
(function(){
function setArticleH(btnReadmore,posi){
var winH = $(window).height();
var articleBox = $("div.article_content");
var artH = articleBox.height();
if(artH > winH*posi){
articleBox.css({
'height':winH*posi+'px',
'overflow':'hidden'
})
btnReadmore.click(function(){
articleBox.removeAttr("style");
$(this).parent().remove();
})
}else{
btnReadmore.parent().remove();
}
}
var btnReadmore = $("#btn-readmore");
if(btnReadmore.length>0){
if(currentUserName){
setArticleH(btnReadmore,3);
}else{
setArticleH(btnReadmore,1.2);
}
}
})()
</script>
</article>
Java7任务并行执行神器:Fork&Join框架的更多相关文章
- 013-多线程-基础-Fork/Join框架、parallelStream讲解
一.概述 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 它同ThreadPoolExecut ...
- Java并发编程--Fork/Join框架使用
上篇博客我们介绍了通过CyclicBarrier使线程同步,可是上述方法存在一个问题,那就是假设一个大任务跑了2个线程去完毕.假设线程2耗时比线程1多2倍.线程1完毕后必须等待线程2完毕.等待的过程线 ...
- Fork/Join框架与Java8 Stream API 之并行流的速度比较
Fork/Join 框架有特定的ExecutorService和线程池构成.ExecutorService可以运行任务,并且这个任务会被分解成较小的任务,它们从线程池中被fork(被不同的线程执行)出 ...
- Java7任务并行执行神器:Fork&Join框架
Fork/Join是什么? Fork/Join框架是Java7提供的并行执行任务框架,思想是将大任务分解成小任务,然后小任务又可以继续分解,然后每个小任务分别计算出结果再合并起来,最后将汇总的结果作为 ...
- 使用Java7提供Fork/Join框架
在Java7在.JDK它提供了多线程开发提供了一个非常强大的框架.这是Fork/Join框架.这是原来的Executors更多 进一步,在原来的基础上添加了并行分治计算中的一种Work-stealin ...
- 使用Java7提供的Fork/Join框架
http://blog.csdn.net/a352193394/article/details/39872923 使用Java7提供的Fork/Join框架 2014-10-07 23:55 4818 ...
- 多线程(五) Fork/Join框架介绍及实例讲解
什么是Fork/Join框架 Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我们再通过For ...
- JAVA中的Fork/Join框架
看了下Java Tutorials中的fork/join章节,整理下. 什么是fork/join框架 fork/join框架是ExecutorService接口的一个实现,可以帮助开发人员充分利用多核 ...
- 聊聊并发(八)——Fork/Join框架介绍
作者 方腾飞 发布于 2013年12月23日 | 被首富的“一个亿”刷屏?不如定个小目标,先把握住QCon上海的优惠吧!2 讨论 分享到:微博微信FacebookTwitter有道云笔记邮件分享 ...
随机推荐
- 直接打印类,调用toString()方法
直接打印类,调用的是继承的Object类的toString()方法,Object类的toString()方法是这样实现的:getClass().getName() + "@" + ...
- 2019-08-02 纪中NOIP模拟B组
T1 [JZOJ1420] 佳肴 题目描述 佳肴就是非常美味的菜的意思,佳肴最关键的是选择好原料. 现在有N种原料,每种原料都有酸度S和苦度B两个属性,当选择多种原料时,总酸度为每种原料的酸度之积,总 ...
- 密码学笔记-一段base64wp
CTF--练习平台 例题: 一段Base64 flag格式:flag{xxxxxxxxxxxxx} 附件: base64.txt 1.base64解码:http://base64.xpcha.com/ ...
- Flink流处理(一)- 状态流处理简介
1. Flink 简介 Flink 是一个分布式流处理器,提供直观且易于使用的API,以供实现有状态的流处理应用.它能够以fault-tolerant的方式高效地运行在大规模系统中. 流处理技术在当今 ...
- 题解【CJOJ1236】【复赛】指数序列求和
P1236 - [复赛]指数序列求和 Description 求1^b+2^b+…+a^b的和除以10000的余数. Input 第一行包含一个正整数N,表示有N组测试数据接下来N行每行包含两个正整数 ...
- HTML学习(7)格式化标签
对文本格式进行编辑的标签.常用: <b>加粗文本</b> <strong>加重语气</strong> 与<b>效果一样,<stro ...
- 百炼OJ - 1003 - Hangover
题目链接 思路 求一个数列的前n项和(1/2, 1/3, ...., 1/n)大于所给数所需的项数. #include<stdio.h> int main() { float a; whi ...
- 排查 k8s 集群 master 节点无法正常工作的问题
搭建的是 k8s 高可用集群,用了 3 台 master 节点,2 台 master 节点宕机后,仅剩的 1 台无法正常工作. 运行 kubectl get nodes 命令出现下面的错误 The c ...
- Win2012或Win2016安装网卡
在电脑安装了Windows Server 2012或者2016等系统之后,可能面临的很大的问题就是没有有线或无线网卡. 1.安装网卡的功能 2.一直到“功能”这部分,选择安装“DirectPlay”和 ...
- Mysql实现级联操作(级联更新、级联删除)(转)
一.首先创建两张表stu,sc create table stu( sid int UNSIGNED primary key auto_increment, name varchar(20) not ...