【JUC】十、ForkJoin

news2024/9/29 11:25:18

文章目录

  • 1、分支合并框架
  • 2、案例
  • 3、ForkJoinTask
  • 4、工作窃取算法
  • 5、ForkJoinPool

一个个任务执行在一个个线程上,倘若某一个任务耗时很久,期间其他线程都无事可做,显然没有利用好多核CPU这一计算机资源,因此,出现了"分而治之"的解决方案。

在这里插入图片描述

1、分支合并框架

Fork/Join即分支合并,用处是把一个大任务拆分成多个子任务来并行处理,最后再合并子任务的结果。(since Java1.7)

  • Fork:把一个复杂的任务进行拆分,大事化小
  • Join:把拆分的子任务的结果做合并

示意图:

在这里插入图片描述

举个实际例子:
在这里插入图片描述

2、案例

以下采用分支合并框架来实现1+2+…+100

在这里插入图片描述

通过继承RecursiveTask类自定义任务,泛型为result的类型:

//自定义任务类继承RecursiveTask
class MyTask extends RecursiveTask<Integer> {

    //拆分差值不超过10,来计算10以内的运算
    private static final int VALUE = 10;
    //拆分起始值
    private int begin;
    //拆分结束值
    private int end;
    //返回结果
    private int result;

    //构造中传入起始值
    public MyTask(int begin, int end) {
        this.begin = begin;
        this.end = end;
    }

    //拆分与合并
    @Override
    protected Integer compute() {
        //判断即将要相加的两个数差值是否大于10
        if (end - begin <= VALUE) {
            for (int i = begin; i <= end; i++) {
                result = result + i;
            }
        //否,则进一步拆分
        } else {
            //中间值
            int middle = (begin+end) /2;
            //左边
            MyTask task01 = new MyTask(begin, middle);
            //右边
            MyTask task02 = new MyTask(middle + 1, end);
            //调用方法拆分
            task01.fork();
            task02.fork();
            //合并结果
            result = task01.join() + task02.join();

        }
        return result;
    }
}

以上自定义Task中体现的思路就是:问题足够小的时候,直接处理,否则就继续拆分。创建forkjoinpool对象,提交任务,获取执行结果:

public class ForkJoinDemo {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建拆分任务对象
        MyTask myTask = new MyTask(0, 100);
        //创建分支合并池对象
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);
        //获取最终合并之后的结果
        Integer result = forkJoinTask.get();
        System.out.println(result);
        //关闭池对象
        forkJoinPool.shutdown();
    }

}

结果:

5050

3、ForkJoinTask

在这里插入图片描述
ForkJoinTask有两个子类:Recursive即递归的意思

  • RecursiveTask:有返回值的任务
  • RecursiveAction:没有返回值的任务

ForkJoinTask还实现了Future接口,即说明是一个可以异步获取结果的任务。常用方法有:

  • fork:分割子任务,判断当前线程是否可以转型为ForkJoinWorkerThread类型,即是不是通过ForkJoinPool线程池执行的ForkJoinTask,是就push到队列里

在这里插入图片描述

  • 合并子任务结果:join
//调用方法拆分
task01.fork();
task02.fork();
//合并结果
result = task01.join() + task02.join();
  • 获取任务执行结果:get,即等待任务执行完成并返回任务计算结果

【方法源码详解参考这篇】

4、工作窃取算法

先看类ForkJoinWorkerThread类,它是执行前面ForkJoinTask的线程。ForkJoin框架使用的线程维护了一个双端队列,并通过工作窃取算法(work-stealing)来提高任务执行的效率。

在这里插入图片描述

工作窃取算法,在ForkJoin框架中就是一个线程的任务队列里的活儿都干完了,就去其他线程维护的任务队列的尾部窃取一个任务来执行。用张网图示意:

在这里插入图片描述

因此:

  • 对于线程自身维护的任务队列,线程自身执行任务的顺序是后进先出
  • 对于窃取其他线程队列的线程,则是先进先出(从队尾窃取并执行)

如图,对于线程1,任务的出入队都在队首,而负责窃取任务的线程2,其从队尾取任务,也就是说,只有线程1的任务队列只剩最后一个任务的时候,才会抢夺一次锁。如此,就大大提高了并发任务的执行效率。

5、ForkJoinPool

FoolJoinPool是运行ForkJoinTask的线程池,同ThreadPoolExecutor一样,也实现了Executor和ExecutorService接口

在这里插入图片描述

任务提交到ForkJoinPool后,池里维护的线程来执行任务

ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);

其构造方法有四个参数:

public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode){
//.....

分别是:

  • parallelism:期望并发数,默认会使用Runtime.getRuntime().availableProcessors()的值,即当前计算机可用的CPU数量
  • factory:创建ForkJoin工作线程的工厂,默认为defaultForkJoinWorkerThreadFactory
  • handler:执行任务时遇到不可恢复的错误时的处理程序,默认为null
  • asyncMode:工作线程获取任务使用FIFO(先进先出)模式还是LIFO模式,默认为LIFO(后进先出)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1235417.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

红队攻防之Goby反杀

若结局非我所愿&#xff0c;那就在尘埃落定前奋力一搏。 本文首发于先知社区&#xff0c;原创作者即是本人 一、弹xss 为了方便&#xff0c;本次直接使用 PhpStudy 进行建站&#xff0c;开启的web服务要为MySQLNginx&#xff0c;这里的 PhpStudy 地址为 http://x.x.x.x&…

AC修炼计划(AtCoder Beginner Contest 329)

传送门&#xff1a;&#xff33;&#xff4b;&#xff59; Inc, Programming Contest 2023&#xff08;AtCoder Beginner Contest 329&#xff09; - AtCoder A&#xff0c;B&#xff0c;C&#xff0c;D 这四道题比较简单&#xff0c;就不多叙述。 E - Stamp 这题是一道比较…

模拟量采集----测量输入的电压

生活中的模拟量有很多 大多都为电压信号和电流信号 今天讲如何测量输入的电压信号 由图中的黄线可知&#xff0c;该运放是采用的同相放大器中的电压跟随器 电压跟随器的特点是电压的输入和输出隔离 同相运放的输入与输出的关系是&#xff1a;输出1R2/R1 在图上对应的就是输…

Spring:IoC,AOP的简单理解与使用

IoC容器 IoC &#xff0c;Spring全家桶各个功能模块的基础&#xff0c;是创建对象的容器。 IoC概念 控制反转&#xff0c;将对象的创建进行反转&#xff0c;常规情况下对象由开发者手动创建&#xff0c;而使用IoC不再需要创建对象&#xff0c;由IoC容器根据需求自动创建项目…

vue实现el-menu与el-tabs联动

效果图如下&#xff1a; 当标签栏很多的时候效果图如下&#xff1a; 左侧菜单布局 &#xff08;$route.path高亮显示激活路由 :default-active"$route.path"&#xff09; <el-menu:default-active"$route.path"class"el-menu-vertical-demo"b…

通达信吊灯止损指标公式,根据波动幅度自动调整止盈止损

吊灯止损指标是由查克勒博(Chuck LeBeau)发明的&#xff0c;亚历山大埃尔德(Alexander Elder)在其著作《走进我的交易室》中介绍了这种止盈止损方法&#xff08;中文版翻译为倒挂式离场法则&#xff09;&#xff0c;它是根据平均真实波幅ATR设置跟踪止损。吊灯止损指标的目的是…

【Java系列】SpringBoot 集成MongoDB 详细介绍

目录 写在前面 一、步骤介绍 步骤 1: 添加 MongoDB 依赖 步骤 2: 配置 MongoDB 连接信息 步骤 3: 创建实体类 步骤 4: 创建 Repository 接口 步骤 5: 使用 Repository 进行操作 二、特殊处理 写在前面 在Spring Boot中集成MongoDB的过程相对简单&#xff0c;以下是一个…

基于单片机公交安全预警系统仿真设计

**单片机设计介绍&#xff0c; 基于单片机公交安全预警系统仿真设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的公交安全预警系统可以被设计成能够实时监测公交车辆的行驶状态&#xff0c;并在发生异常情况时进行…

【Computer Vision Foundation】全球计算机视觉基金会论文网

计算机视觉基金会&#xff08;Computer Vision Foundation&#xff0c;简称CVF&#xff09;是一个致力于推动计算机视觉领域研究和发展的组织。以下是关于计算机视觉基金会的一些基本信息&#xff1a; 成立目的&#xff1a; CVF成立的目的是促进计算机视觉领域的学术研究、技术…

【微服务】SaaS云智慧工地管理平台源码

智慧工地系统是一种利用人工智能和物联网技术来监测和管理建筑工地的系统。它可以通过感知设备、数据处理和分析、智能控制等技术手段&#xff0c;实现对工地施工、设备状态、人员安全等方面的实时监控和管理。 一、智慧工地让工程施工智能化 1、内容全面&#xff0c;多维度数…

【运维】永久关闭selinux不当,导致无法启动

现象: 卡centos loading进度条 按esc键发现,启动报错: Failed to load SElinux policy ,freezing 可能的原因: selinuxdisabled 写错成disable 或者 错误的把selinuxtype改了&#xff0c;要改文中红框的部分。 解决方案: 1. 重启 2. 出现选择画面的时候 按e 3. 方向下键…

Shell判断:模式匹配:case(二)

简单的JumpServer 1、需求&#xff1a;工作中&#xff0c;我们需要管理N多个服务器。那么访问服务器就是一件繁琐的事情。通过shell编程&#xff0c;编写跳板程序。当我们需要访问服务器时&#xff0c;看一眼服务器列表名&#xff0c;按一下数字&#xff0c;就登录成功了。 2、…

【Vue】响应式与数据劫持

目录 前言 响应式 Vue的响应式是如何实现的 数据劫持 Vue中的data属性都具有响应式 Vue后期添加的属性如何使其具有响应式 数组的响应式处理 如何使用数组下标去修改可以具有响应式呢 前言 什么是响应式&#xff1f;数据劫持是什么&#xff1f;Vue响应式是如何实现的&a…

VScode调试没有反应

点击调试按钮后没反应 有可能是vscode中安装的python插件版本问题 可以通过重新安装比较旧一点的python尝试解决此问题 步骤如下&#xff1a; 然后从中选择比当前版本更低的版本即可 安装完成后需重启vscode

Unity中Shader的PBR的基础知识与理论

文章目录 前言一、什么是PBR二、什么是PBS在这里插入图片描述 三、PBS的核心理论1、物质的光学特性&#xff08;Substance Optical Properties&#xff09;2、微平面理论&#xff08;Microfacet Theory&#xff09;3、能量守恒&#xff08;Energy Conservation&#xff09;4、菲…

Linux中的MFS分布式文件系统

目录 一、MFS分布式文件系统 1、MooseFS简介 2、Moose File System的体系结构 &#xff08;1&#xff09;MooseFS Master &#xff08;2&#xff09;MooseFS Chunk Server &#xff08;3&#xff09;MooseFS Metalogger &#xff08;4&#xff09;MooseFS Client &…

InnoDB 的一次更新事务是怎么实现的?

大体流程&#xff1a; 步骤: 1.加载数据到缓存中&#xff08;Buffer Pool&#xff09;&#xff1a; 在进行数据更新时&#xff0c;InnoDB首先会在缓冲池&#xff08;Buffer Pool&#xff09;中查找该记录是否已经在内存中。如果记录不在内存中&#xff0c;会将需要更新的数据…

django+drf+vue 简单系统搭建 (3) - 基于类的视图

传统Django中有基于类的视图&#xff0c;Drf中自然也有&#xff0c;目的都是实现功能的模块化继承&#xff0c;封装&#xff0c;减少重复代码。 首先在视图中新增下面代码&#xff1a; # simpletool/views.pyfrom rest_framework.views import APIView from simpletool.seria…

matplotlib violinplot换颜色

本来用的是箱图&#xff0c;后来发现这个图更好看&#xff0c;就想要学习一下&#xff0c;官方有给教程&#xff0c;当然可以直接学习 https://matplotlib.org/stable/gallery/statistics/customized_violin.html 以上是官方给的&#xff0c;效果是这个样子的 这个从最基本的蓝…

redis运维(十二)

一 位图 ① 概念 1、说明&#xff1a;位图还是在操作字符串2、位图玩字符串在内存中存储的二进制3、ASCII字符通过映射转化为二进制4、操作的是字符串value ② ASCII字符铺垫 1、控制ASCII字符 2、ASCII可显示字符 ③ SETBIT 细节&#xff1a; setbit 命令的返回值是之…