本文源码:GitHub·点这里 || GitEE·点这里

一、Fork/Join框架

Java提供Fork/Join框架用于并行执行任务,核心的思想就是将一个大任务切分成多个小任务,然后汇总每个小任务的执行结果得到这个大任务的最终结果。

这种机制策略在分布式数据库中非常常见,数据分布在不同的数据库的副本中,在执行查询时,每个服务都要跑查询任务,最后在一个服务上做数据合并,或者提供一个中间引擎层,用来汇总数据:

核心流程:切分任务,模块任务异步执行,单任务结果合并;在编程里面,通用的代码不多,但是通用的思想却随处可见。

二、核心API和方法

1、编码案例

基于1+2…+100的计算案例演示Fork/Join框架基础用法。

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;public class ForkJoin01 {public static void main (String[] args) {int[] numArr = new int[100];for (int i = 0; i < 100; i++) {numArr[i] = i + 1;}ForkJoinPool pool = new ForkJoinPool();ForkJoinTask<Integer> forkJoinTask =pool.submit(new SumTask(numArr, 0, numArr.length));System.out.println("合并计算结果: " + forkJoinTask.invoke());pool.shutdown();}
}
/*** 线程任务*/
class SumTask extends RecursiveTask<Integer> {/** 切分任务块的阈值* 如果THRESHOLD=100* 输出:main【求和:(0...100)=5050】 合并计算结果: 5050*/private static final int THRESHOLD = 100;private int arr[];private int start;private int over;public SumTask(int[] arr, int start, int over) {this.arr = arr;this.start = start;this.over = over;}// 求和计算private Integer sumCalculate () {Integer sum = 0;for (int i = start; i < over; i++) {sum += arr[i];}String task = "【求和:(" + start + "..." + over + ")=" + sum +"】";System.out.println(Thread.currentThread().getName() + task);return sum ;}@Overrideprotected Integer compute() {if ((over - start) <= THRESHOLD) {return sumCalculate();}else {int middle = (start + over) / 2;SumTask left = new SumTask(arr, start, middle);SumTask right = new SumTask(arr, middle, over);left.fork();right.fork();return left.join() + right.join();}}
}

2、核心API说明

ForkJoinPool:线程池最大的特点就是分叉(fork)合并(join)模式,将一个大任务拆分成多个小任务,并行执行,再结合工作窃取算法提高整体的执行效率,充分利用CPU资源。

ForkJoinTask:运行在ForkJoinPool的一个任务抽象,可以理解为类线程但是比线程轻量的实体,在ForkJoinPool中运行的少量ForkJoinWorkerThread可以持有大量的ForkJoinTask和它的子任务,同时也是一个轻量的Future,使用时应避免较长阻塞或IO。

继承子类:

  • RecursiveAction:递归无返回值的ForkJoinTask子类;
  • RecursiveTask:递归有返回值的ForkJoinTask子类;

核心方法:

  • fork():在当前线程运行的线程池中创建一个子任务;
  • join():模块子任务完成的时候返回任务结果;
  • invoke():执行任务,也可以实时等待最终执行结果;

3、核心策略说明

任务拆分

ForkJoinPool基于分治算法,将大任务不断拆分下去,每个子任务再拆分一半,直到达到最阈值设定的任务粒度为止,并且把任务放到不同的队列里面,然后从最底层的任务开始执行计算,并且往上一层合并结果,这样用相对少的线程处理大量的任务。

工作窃取算法

大任务被分割为独立的子任务,并且子任务分别放到不同的队列里,并为每个队列创建一个线程来执行队列里的任务,假设线程A优先把分配到自己队列里的任务执行完毕,此时如果线程E对应的队列里还有任务等待执行,空闲的线程A会窃取线程E队列里任务执行,并且为了减少窃取任务时线程A和被窃取任务线程E之间的发生竞争,窃取任务的线程A会从队列的尾部获取任务执行,被窃取任务线程E会从队列的头部获取任务执行。

工作窃取算法的优点:线程间的竞争很少,充分利用线程进行并行计算,但是在任务队列里只有一个任务时,也可能会存在竞争情况。

三、应用案例分析

在后端系统的业务开发中,可用做权限校验,批量定时任务状态刷新等各种功能场景:

如上图,假设数据的主键id分段如下,数据场景可能是数据源的连接信息,或者产品有效期类似业务,都可以基于线程池任务处理:

权限校验

基于数据源的连接信息,判断数据源是否可用,例如:判断连接是否可用,用户是否有库表的读写权限,在数据源多的情况下,基于线程池快速校验。

状态刷新

在定时任务中,经常见到状态类的刷新操作,例如判断产品是否在有效期范围内,在有效期范围之外,把数据置为失效状态,都可以利用线程池快速处理。

四、源代码地址

GitHub·地址
https://github.com/cicadasmile/java-base-parent
GitEE·地址
https://gitee.com/cicadasmile/java-base-parent

推荐阅读:Java并发系列

序号 文章标题
01 Java并发:线程的创建方式,状态周期管理
02 Java并发:线程核心机制,基础概念扩展
03 Java并发:多线程并发访问,同步控制
04 Java并发:线程间通信,等待/通知机制
05 Java并发:悲观锁和乐观锁机制
06 Java并发:Lock机制下API用法详解

Java并发编程(07):Fork/Join框架机制详解相关推荐

  1. Java并发编程:线程封闭和ThreadLocal详解

    什么是线程封闭 当访问共享变量时,往往需要加锁来保证数据同步.一种避免使用同步的方式就是不共享数据.如果仅在单线程中访问数据,就不需要同步了.这种技术称为线程封闭.在Java语言中,提供了一些类库和机 ...

  2. java并发编程之线程的生命周期详解

    java线程从创建到销毁,一共会有6个状态,不一定都经历,有可能只经历部分: NEW:初始状态,线程被创建,但是还没有调用start方法. RUNNABLED:运行状态,java线程把操作系统中的就绪 ...

  3. Java并发编程系列之CountDownLatch用法及详解

    背景 前几天一个同事问我,对这个CountDownLatch有没有了解想问一些问题,当时我一脸懵逼,不知道如何回答.今天赶紧抽空好好补补.不得不说Doug Lea大师真的很牛,设计出如此好的类. 1. ...

  4. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(一)

    文章大纲 引言 一.Android Storage Access Framework 二.Storage Access Framework 的主要角色成员 1.Document Provider 文件 ...

  5. Android 进阶——Framework 核心之Android Storage Access Framework(SAF)存储访问框架机制详解(二)

    文章大纲 引言 一.DirectFragment 1.当选中DirectoryFragment中RecyclerView的Item时 2.选中DirectoryFragment中RecyclerVie ...

  6. Java网络编程(6)NIO - Channel详解

    前言 NIO的三个核心组件:Buffer.Channel.Selector Java网络编程(4)NIO的理解与NIO的三个组件完成了大概的了解 Java网络编程(5)NIO - Buffer详解详细 ...

  7. Java 7:满足Fork / Join框架

    JSR-166(y)是Java 7中包含的此新功能的正式名称.如果您发现名称中有一个" y",这是因为自Java 5起就添加了JSR-166(并发实用程序) ,但它不会就此停止,因 ...

  8. 【java并发系列】Fork/Join任务(转)

    原文链接 当我们需要执行大量的小任务时,有经验的Java开发人员都会采用线程池来高效执行这些小任务.然而,有一种任务,例如,对超过1000万个元素的数组进行排序,这种任务本身可以并发执行,但如何拆解成 ...

  9. 多线程高并发编程(8) -- Fork/Join源码分析

    一.概念 Fork/Join就是将一个大任务分解(fork)成许多个独立的小任务,然后多线程并行去处理这些小任务,每个小任务处理完得到结果再进行合并(join)得到最终的结果. 流程:任务继承Recu ...

最新文章

  1. cisco 路由器监控路由连通性_Cisco-路由器配置DHCP小实验
  2. python3.0安卓版-qPython 3h下载
  3. mybatis 配置 mysql连接池_spring 5.x 系列第5篇 —— 整合 mybatis + druid 连接池 (xml配置方式)...
  4. Python中操作mysql的pymysql模块详解
  5. 洛谷 U10783 名字被和谐了
  6. linux获取windows的主机名,获取网络许可主机名和主机 ID 的步骤
  7. 由href return false 来看阻止默认事件
  8. 放出几个E-book,经典啊,Ruby的
  9. 一名技术leader的工作随笔
  10. android fake camera,码市 - No.22987 - android fake camera - 其他
  11. 陈抟(tuán)《心相篇》
  12. VMware虚拟机安装Windows11(无需设置TMP密码)
  13. 电脑连接树莓派3B+
  14. 技术人如何才能不焦虑
  15. 如何快速实现在网页中调用文档扫描仪 (2)
  16. 快速入门electron之实现窗口拖拽
  17. 必不可少的数学基础-数列的柯西收敛准则
  18. MOS与三极管的控制使用简介
  19. POI导出Excel表格,去掉数字框的左上角绿色的小三角
  20. 免费电子书籍下载站点●大全

热门文章

  1. python自带的解释器叫做_21条python面试题,值得收藏!
  2. Android开发:5-1、Adopter
  3. (王道408考研操作系统)第四章文件管理-第一节6:文件基本操作
  4. (王道408考研操作系统)第四章文件管理-第一节1:文件管理初识
  5. (计算机组成原理)第五章中央处理器-第四节4:微程序控制单元设计
  6. 回溯算法详解:理论+基础类回溯题解
  7. LeetCode 130 被围绕的区域
  8. phpstudy下载、安装、配置、网站部署、卸载(windows下php、apache、nginx环境测试)
  9. Windows获取本机主机IP信息
  10. Linux lsof命令使用详细