一、fork/join

Java 7开始引入了一种新的Fork/Join线程池,它可以执行一种特殊的任务:把一个大任务拆成多个小任务并行执行。

我们举个例子:如果要计算一个超大数组的和,最简单的做法是用一个循环在一个线程内完成:

┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘

还有一种方法,可以把数组拆成两部分,分别计算,最后加起来就是最终结果,这样可以用两个线程并行执行:

┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘

如果拆成两部分还是很大,我们还可以继续拆,用4个线程并行执行:

┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘
┌─┬─┬─┬─┬─┬─┐
└─┴─┴─┴─┴─┴─┘

这就是Fork/Join任务的原理:判断一个任务是否足够小,如果是,直接计算,否则,就分拆成几个小任务分别计算。

这个过程可以反复“裂变”成一系列小任务。

二、实例-使用Fork/Join对大数据进行并行求和:

package com.itranswarp.learnjava;import java.util.Random;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;/*** Learn Java from https://www.liaoxuefeng.com/* * @author liaoxuefeng*/
public class Main {public static void main(String[] args) throws Exception {// 创建2000个随机数组成的数组:long[] array = new long[2000];// 期待的总和long expectedSum = 0;// 赋值随机数for (int i = 0; i < array.length; i++) {array[i] = random();expectedSum += array[i];}System.out.println("Expected sum: " + expectedSum);// fork/join:ForkJoinTask<Long> task = new SumTask(array, 0, array.length);// 开始时间long startTime = System.currentTimeMillis();// 线程开始运算Long result = ForkJoinPool.commonPool().invoke(task);// 结束时间long endTime = System.currentTimeMillis();System.out.println("Fork/join sum: " + result + " in " + (endTime - startTime) + " ms.");}static Random random = new Random(0);static long random() {// 该方法的作用是生成一个随机的int值,该值介于[0,n)的区间,也就是0到n之间的随机int值,包含0而不包含n。return random.nextInt(10000);}
}// fork/join
class SumTask extends RecursiveTask<Long> {// 数组大于500则分叉static final int THRESHOLD = 500;long[] array;int start;int end;// 要计算的数组SumTask(long[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}// 计算@Overrideprotected Long compute() {// 如果任务足够小,直接计算:if (end - start <= THRESHOLD) {long sum = 0;for (int i = start; i < end; i++) {sum += this.array[i];// 故意放慢计算速度:try {Thread.sleep(2);} catch (InterruptedException e) {}}return sum;}// 任务太大:else{// 任务一分为二int middle = (end + start) / 2;System.out.println(String.format("split %d~%d ==> %d~%d, %d~%d", start, end, start, middle, middle, end));// 分别建立两个任务SumTask subtask1 = new SumTask(this.array, start, middle);SumTask subtask2 = new SumTask(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;}}
}

观察上述代码的执行过程,一个大的计算任务0~2000首先分裂为两个小任务0~1000和1000~2000,这两个小任务仍然太大,继续分裂为更小的0~500,500~1000,1000~1500,1500~2000,最后,计算结果被依次合并,得到最终结果。

因此,核心代码SumTask继承自RecursiveTask,在compute()方法中,关键是如何“分裂”出子任务并且提交子任务:

class SumTask extends RecursiveTask<Long> {protected Long compute() {// “分裂”子任务:SumTask subtask1 = new SumTask(...);SumTask subtask2 = new SumTask(...);// invokeAll会并行运行两个子任务:invokeAll(subtask1, subtask2);// 获得子任务的结果:Long subresult1 = subtask1.join();Long subresult2 = subtask2.join();// 汇总结果:return subresult1 + subresult2;}
}

Fork/Join线程池在Java标准库中就有应用。

Java标准库提供的java.util.Arrays.parallelSort(array)可以进行并行排序,它的原理就是内部通过Fork/Join对大数组分拆进行并行排序,在多核CPU上就可以大大提高排序的速度。

三、小结

Fork/Join是一种基于“分治”的算法:通过分解任务,并行执行,最后合并结果得到最终结果。

ForkJoinPool线程池可以把一个大任务分拆成小任务并行执行,任务类必须继承自RecursiveTaskRecursiveAction

使用Fork/Join模式可以进行并行计算以提高效率。

https://www.liaoxuefeng.com/wiki/1252599548343744/1306581226487842

Java 线程 fork join 是什么 怎么用相关推荐

  1. Java线程Fork/Join思想及实现

    最近在看线程这一块的东西,所以之前的那篇文章就是用来记录的,但看起来好简单的样子,哈哈哈! 这两天看的是Fork/Join 分而治之的思想,Doug Lea大师的JUC还是挺强的,学并发编程应该没有人 ...

  2. System Verilog线程——fork join的理解使用

    本文参考绿皮书第七章,线程及其线程间的通信,Verilog HDL A guide to digital design and synthesis 2nd第七章.主要对于begin-end,fork- ...

  3. java fork_浅谈Java的Fork/Join并发框架

    前几天有写到整合并发结果的文章,于是联想到了Fork/Join.因为在我看来整合并发结果其实就是Fork/Join中的Join步骤.所以今天我就把自己对Fork/Join一些浅显的理解记录下来. 1. ...

  4. 浅谈Java的Fork/Join并发框架

    1. Fork/Join是什么 Oracle的官方给出的定义是:Fork/Join框架是一个实现了ExecutorService接口的多线程处理器.它可以把一个大的任务划分为若干个小的任务并发执行,充 ...

  5. Java并发-Fork/Join框架

    参考博客:https://www.infoq.cn/article/fork-join-introduction 1. 什么是 Fork/Join 框架 Fork/Join 框架是 Java7 提供了 ...

  6. java forkjoin 简书_浅谈Java的Fork/Join并发框架

    1. Fork/Join是什么 Oracle的官方给出的定义是:Fork/Join框架是一个实现了ExecutorService接口的多线程处理器.它可以把一个大的任务划分为若干个小的任务并发执行,充 ...

  7. java 线程方法join的简单总结

    虽然关于讨论线程join方法的博客已经很多了,不过个人感觉挺多都讨论得不够全面,所以我觉得有必要对其进行一个全面的总结. 一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间 ...

  8. java线程中join方法的简单讲解

    一.作用 Thread类中的join方法的主要作用就是同步,它可以使得线程之间的并发执行变为串行执行.具体看代码: public class Test {public static void main ...

  9. Java并发编程(07):Fork/Join框架机制详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.Fork/Join框架 Java提供Fork/Join框架用于并行执行任务,核心的思想就是将一个大任务切分成多个小任务,然后汇总每个小任务 ...

  10. Java线程面试的前50个问题,面向初学者和经验丰富的程序员

    您可以参加任何Java面试,无论是大四还是中级,经验或新来的人,一定会看到线​​程,并发和多线程中的几个问题. 实际上,这种内置的并发支持是Java编程语言的最强优势之一,并帮助它在企业界和程序员中同 ...

最新文章

  1. 什么时候可以全面升级鸿蒙系统,华为已做好全面升级准备,鸿蒙系统将替换底层安卓系统...
  2. java同步互斥功能检测_猿考研之操作系统篇三(进程同步,管程,死锁)
  3. Spring Cloud Alibaba基础教程:Sentinel Dashboard同步Apollo存储规则
  4. 经常使用的MySQL语句整理
  5. 34 年了,“杀”不死的 Perl!
  6. 部署Docker----解决删除none镜像问题
  7. Cannot attach the file as database 'membership'.
  8. 2 追踪光线=》2.6 反射光线
  9. jetson windows_生命不息,折腾不止:Jetson Nano填坑之软件篇
  10. php 打印 域名ip_php如何获取域名IP地址代码函数
  11. CF438D The Child and Sequence
  12. vb导出mysql字段名_VB获取数据库字段名
  13. Windows 平台上使用 cwRsync做文件同步
  14. osgEarth基础入门
  15. 发布地图服务时导入已有的tpk切片包作为缓存
  16. 无纸化测评系统计算机考试试题,2015年9月计算机二级《Access》无纸化试卷(1)
  17. 大学该不该开python教学_#51CTO学院四周年# python学习感受和一些愚见
  18. Android studio adb 不是内部或外部指令,也不是可运行的程序
  19. 使用OpenCV检测摄像头视频中的人脸
  20. 教务排课系统毕业设计,大学排课系统设计与实现,排课系统论文作品参考

热门文章

  1. 将序列设置为字段的默认值 - oracle
  2. Revit二次开发之TaskDialog
  3. [Python WEB开发] 使用WSGI开发类Flask框架 (二)
  4. Okhttp3 使用和原理(DEMO)
  5. 【bzoj1520】[POI2006]Szk-Schools 费用流
  6. VS2013 update4+Cocos2d-x 3.7 Win8下安装方法及配置
  7. 解密小程序码:36条放射线
  8. 【作业报告】作业5 四则运算 测试与封装 5.1
  9. Centos系统设置
  10. sqlserver2008的数据库自动备份方法(转载)