ForkJoin全解1:简单使用与大致实现原理
1、 使用示例
import java.lang.reflect.Method;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ThreadLocalRandom;
public class ForkJoinDemo {
public static void main(String[] args) throws Exception{
//使用ForkJoinPool来执行任务
ForkJoinPool forkJoinPool = new ForkJoinPool();
//生成一个计算任务,负责计算1+2+3+4
CountTaskTmp task = new CountTaskTmp(1, 100000000);
long r = forkJoinPool.invoke(task);
System.out.println(r);
}
}
@SuppressWarnings("serial")
// RecursiveTask是ForkJoinTask的子类
class CountTaskTmp extends RecursiveTask<Long> {
private static final long THRESHOLD = 10000000;
private long start;
private long end;
public CountTaskTmp(long start, long end) {
this.start = start;
this.end = end;
}
//实现compute 方法来实现任务切分和计算
@Override
protected Long compute() {
long sum = 0;
boolean canCompute = (end - start) <= THRESHOLD;
if (canCompute) {
for (long i = start; i <= end; i++)
sum += i;
} else {
//如果任务大于阀值,就分裂成两个子任务计算
long mid = (start + end) / 2;
CountTaskTmp leftTask = new CountTaskTmp(start, mid);
CountTaskTmp rightTask = new CountTaskTmp(mid + 1, end);
System.out.println("fork开始");
//执行子任务
leftTask.fork();
rightTask.fork();
System.out.println("fork完毕");
//等待子任务执行完,并得到结果
System.out.println("join开始");
long leftResult = leftTask.join();
long rightResult = rightTask.join();
System.out.println("join完毕");
sum = leftResult + rightResult;
}
return sum;
}
}
2、简写说明:
下面:
ForkJoinWorkerThread简写为Thread
ForkJoinWorkerPool简写为pool
ForkJoinWorkerTask简写为task
workQueue简写为queue
3、任务窃取大致实现原理
在上面示例中,我们通过THRESHOLD字段指定每个任务计算1千万个数据,如果超过一千万,则使用二分法把任务切分为leftTask和rightTask。如果leftTask和rightTask还是超过一千万数据,还会继续切分,当任务足够小,就开始真正执行计算逻辑。整个过程有点类似递归。下面使用伪码简单看下工作过程:
class ForkJoinTask{
fork(){
forJoinPool.push(this) //把任务提交到pool执行
}
T join(){
synchronized(this){
wait();//等待任务执行完毕,任务执行完毕会调用notify
}
return getRawResult();//返回当前task的结果
}
}
class WorkQueue{
ForkJoinThread owner;
ForkJoinTask array[];//存放task的数组
int top=base=0;
push(task){
//如果数组长度不够了,则创建一个长度更大的数组
growArray()
//把task放到array
array[top++]=task
}
//当这个workQueue的所属线程执行任务时,调用pop获取task
pop(){
return array[top--];
}
//当其他线程要窃取这个队列的任务时,使用poll窃取任务。通过base和top两个变量,array成了双向队列。
// pop是后进先出,而poll则是先进先出。当队列的owner执行自身队列中的task时,通过pop获得任务,
//而其他队列要窃取该队列的task时,则用该队列的poll进行任务窃取
poll(){
return array[base++];
}
growArray(){
//当array大小不够时,创建更大的数组,并把旧数组的元素拷贝到新数组
}
}
class ForkJoinPool{
WorkQueue workQueues[];//workQueue保存task
push(task){
//从workQueues选择一个工作队列,将task放入其中
selectOneWorkQueueFromWorkQueues().add(task)
signalWork(); //通知worker执行任务
}
signalWork(){
if(线程池每有足够的活动线程){
//使用Unsafe的unpark唤醒休眠的线程或调用createWorker创建新线程,并启动该线程
}
}
createWorker(){
new ForkJoinThread(this).start();
}
// ForkJoinThread构造函数中调用,借此把新new出来的ForkJoinThread注册到ForkJoinPool
registerWorker(ForkJoinThread thread){
WorkerQueue workQueue=new WorkerQueue();
// 简单起见,这里暂时理解randomIndex是一个小于workQueues长度的随机数
workQueues[randomIndex]=workQueue;
workQueue.owner=thread
return workerQueue;
}
}
class ForkJoinThread{//Thread的子类
ForkJoinPool pool;
WorkQueue workQueue;
ForkJoinThread(ForkJoinPool pool){
this.pool=pool;
this. workQueue=pool.registerWorker(this);
}
run(){//调用Thread的start方法时,run方法就会被调用
while(!terminate){
//不断执行task,每当任务执行完毕,执行notifyall通知所有等待的worker
//当自身task执行完就从pool中随机选择workQueue,并窃取该workQueue的任务来执行
//如果窃取不到任务,且当前worker由于调用了join,在等待其他线程的任务完成,则当前线程休眠
//如果窃取不到任务,且无需等待其他线程任务的执行,则线程终止
}
}
————————————————
版权声明:本文为CSDN博主「花公子丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yu766588220/article/details/106870548
ForkJoin全解1:简单使用与大致实现原理的更多相关文章
- Mybatis系列全解(三):Mybatis简单CRUD使用介绍
封面:洛小汐 作者:潘潘 在理解中执行,在执行中理解,学习技术也循此道. 前言 上一篇文章 <Mybatis系列全解(二):Mybatis简介与环境搭建> ,我们对 Mybatis 做了初 ...
- 第48章 MDK的编译过程及文件类型全解—零死角玩转STM32-F429系列
第48章 MDK的编译过程及文件类型全解 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.co ...
- RAID技术全解图解-RAID0、RAID1、RAID5、RAID100【转】
图文并茂 RAID 技术全解 – RAID0.RAID1.RAID5.RAID100…… RAID 技术相信大家都有接触过,尤其是服务器运维人员,RAID 概念很多,有时候会概念混淆.这篇文章为网络转 ...
- RAID 技术全解
图文并茂 RAID 技术全解 – RAID0.RAID1.RAID5.RAID100-- RAID 技术相信大家都有接触过,尤其是服务器运维人员,RAID 概念很多,有时候会概念混淆.这篇文章为网络转 ...
- Mybatis系列全解(八):Mybatis的9大动态SQL标签你知道几个?提前致女神!
封面:洛小汐 作者:潘潘 2021年,仰望天空,脚踏实地. 这算是春节后首篇 Mybatis 文了~ 跨了个年感觉写了有半个世纪 ... 借着女神节 ヾ(◍°∇°◍)ノ゙ 提前祝男神女神们越靓越富越嗨 ...
- Mybatis系列全解(六):Mybatis最硬核的API你知道几个?
封面:洛小汐 作者:潘潘 2020 年的大疫情,把世界撕成几片. 时至今日,依旧人心惶惶. 很庆幸,身处这安稳国, 兼得一份安稳工. · 东家常讲的一个词:深秋心态 . 大势时,不跟风.起哄, 萧条时 ...
- Mybatis系列全解(四):全网最全!Mybatis配置文件XML全貌详解
封面:洛小汐 作者:潘潘 做大事和做小事的难度是一样的.两者都会消耗你的时间和精力,所以如果决心做事,就要做大事,要确保你的梦想值得追求,未来的收获可以配得上你的努力. 前言 上一篇文章 <My ...
- Mybatis系列全解(二):Mybatis简介与环境搭建
封面:洛小汐 作者:潘潘 Mybatis 是一套持久层框架,灵活易用,特别流行. 前言 Mybatis系列全解,我们预计准备10+篇文章,让我们了解到 Mybatis 的基本全貌,真正从入门到上手,从 ...
- IOS-UITextField-全解
IOS-UITextField-全解 //初始化textfield并设置位置及大小 UITextField *text = [[UITextField alloc]initWithFrame: ...
- 什么是JavaScript闭包终极全解之一——基础概念
本文转自:http://www.cnblogs.com/richaaaard/p/4755021.html 什么是JavaScript闭包终极全解之一——基础概念 “闭包是JavaScript的一大谜 ...
随机推荐
- OpenAI使用AI编程给出了数数问题的解决方案 —— 如何解决ChatGPT不会数数的问题
总所周知的一个问题,那就是ChatGPT不会数数,不过今天突然发现OpenAI给出了一个神奇的解决方法,那就是AI编程. 问题案例如下: The text provided will be analy ...
- 接口测试中Groovy引擎的接入实现!
接口测试中Groovy可以作为上下游接口参数化传递的前置脚本和后置脚本使用,无缝衔接Java语法,groovy的引入对于动态参数化的设置方便很多. 其中核心部分就是接入groovy的引擎,下面介绍gr ...
- Abp源码分析之Abp本地化
aspnetcore mvc 实现本地化 新建mvc项目 修改Program.cs using Microsoft.AspNetCore.Localization; using Microsoft.A ...
- php yaconf扩展
在了解到PHP鸟哥还有这个扩展后,我安装尝试了一下 在这里有介绍 https://pecl.php.net/package/yaconf 这里有更详细的代码和说明 https://github.co ...
- Java线程:新特征-条件变量
条件变量是Java5线程中很重要的一个概念,顾名思义,条件变量就是表示条件的一种变量.但是必须说明,这里的条件是没有实际含义的,仅仅是个标记而已,并且条件的含义往往通过代码来赋予其含义. 这里的条 ...
- golang之增加版本信息功能
在实际开发中,当开发完一个 apiserver 特性后,会编译 apiserver 二进制文件并发布到生产环境,很多时候为了定位问题和出于安全目的(不能发错版本),我们需要知道当前 apiserver ...
- linux之Zip
安装: apt-get) apt-get install zip yum) yum install -y unzip zip 语法: zip [选项] 压缩包名 源文件或源目录列表 注意,zip 压缩 ...
- redis 使用lua 生成流水号
在实际的业务场景中,我们会用到流水号. 之前的流水号做法是,使用redis的全局锁.然后对数据库进行更新,数据库更新 这个也会有一些问题,比如对于同一个流水号,多个线程去更新,由于事务比较长,那么就会 ...
- k8s~service和deployment中的spec.selector
service和deployment中的spec.selector 在 Kubernetes 中,Service 和 Deployment 的 spec.selector 在使用上是有一些不同之处的, ...
- uniapp+vue3酒店预订|vite5+uniapp预约订房系统模板(h5+小程序+App端)
自研uni-app+vue3+uv-ui跨三端仿同程/携程酒店预订系统Uni-Vue3-WeTrip. uniapp-vue3-wetrip原创基于vite5+uniapp+pinia2+uni-ui ...