【揭秘】RecursiveTask全面解析

【揭秘】RecursiveTask全面解析 - 程序员古德

内容概要

RecursiveTask的优点在于能够将复杂任务递归分解为更小的子任务,从而提高处理效率,通过ForkJoinPool执行,RecursiveTask能充分利用多核处理器资源,实现任务的并行化处理,大大加快了计算速度,此外,它还简化了并行编程的复杂性,使开发者能够更专注于业务逻辑的实现。

官方文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/RecursiveTask.html

核心概念

RecursiveTask 主要实现递归任务,它在并发编程中经常被使用,特别是在处理那些可以分解为更小的子问题的算法时,RecursiveTask 的主要用途是解决以下问题:

  1. 递归并行计算:当一个任务可以分解为几个子任务,并且这些子任务可以并行执行时,RecursiveTask 非常有用,通过将问题分解为更小的子问题,并利用多线程并行处理这些子问题,可以显著提高算法的执行效率。
  2. 数据分片:当处理大规模数据集时,可以将数据集分成较小的片段(或“分片”),每个片段可以在单独的线程上处理,RecursiveTask 可以用于定义如何将一个大的数据集分解为小的分片,并如何处理这些分片。
  3. 优化递归:在传统的递归算法中,如果递归深度太大,可能会导致栈溢出,使用 RecursiveTask 可以将一个大问题分解为多个小问题,从而减少了单个递归调用的深度,降低了栈溢出的风险。
  4. 简化并发编程RecursiveTask 提供了一种结构化的方式来编写并发代码,使得代码更容易理解和维护,它还提供了许多有用的工具和机制,如任务拆分、依赖管理、结果合并等,使得并发编程更加便捷。

使用 RecursiveTask 尤其要注意子任务之间不能有共享状态或相互依赖,而且子任务可以独立地完成,如果任务不是可并行化的,使用 RecursiveTask 可能会导致错误的结果或不可预期的行为。

代码案例

RecursiveTaskForkJoinTask 的一个子类,通常用于表示可以并行执行的任务,特别是那些可以递归拆分成更小的子任务的任务,下面是使用 RecursiveTask 的代码案例,该代码计算一个整数数组的元素之和,如下代码:

import java.util.concurrent.ForkJoinPool;  
import java.util.concurrent.RecursiveTask;  
  
public class SumArrayTask extends RecursiveTask<Integer> {  
  
    private static final int THRESHOLD = 10; // 阈值,当数组长度小于此值时,不再拆分任务  
    private final int[] array;  
    private final int start;  
    private final int end;  
  
    public SumArrayTask(int[] array) {  
        this(array, 0, array.length);  
    }  
  
    private SumArrayTask(int[] array, int start, int end) {  
        this.array = array;  
        this.start = start;  
        this.end = end;  
    }  
  
    @Override  
    protected Integer compute() {  
        // 如果任务足够小,直接计算结果  
        if (end - start <= THRESHOLD) {  
            int sum = 0;  
            for (int i = start; i < end; i++) {  
                sum += array[i];  
            }  
            return sum;  
        } else {  
            // 拆分任务  
            int mid = start + (end - start) / 2;  
            SumArrayTask leftTask = new SumArrayTask(array, start, mid);  
            SumArrayTask rightTask = new SumArrayTask(array, mid, end);  
  
            // 递归执行任务并等待结果  
            invokeAll(leftTask, rightTask);  
            return leftTask.join() + rightTask.join();  
        }  
    }  
  
    public static void main(String[] args) {  
        int[] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20};  
  
        // 创建一个 ForkJoinPool  
        ForkJoinPool pool = new ForkJoinPool();  
  
        // 提交任务并获取结果  
        SumArrayTask task = new SumArrayTask(array);  
        int sum = pool.invoke(task);  
  
        // 输出结果  
        System.out.println("Sum of array elements: " + sum);  
  
        // 关闭 ForkJoinPool(通常不是必须的,因为它会在所有任务完成后自动关闭)  
        pool.shutdown();  
    }  
}

上面的代码定义了一个 SumArrayTask 类,它继承自 RecursiveTaskSumArrayTask 的任务是计算一个整数数组的子数组的元素之和,如果子数组的长度小于一个阈值(这里设置为 10),则直接计算结果;否则,任务会被拆分成两个更小的子任务,分别计算左半部分和右半部分的和,然后再将这两个和相加得到最终结果。

运行上面代码,会有如下输出结果:

Sum of array elements: 210

核心API

RecursiveTaskForkJoinTask 的一个子类,用于支持可以递归划分并且可能需要执行大量计算的任务,RecursiveTask 有一个显著的特点:它有返回值,这与其他基于 ForkJoinPool 的任务(如 RecursiveAction)不同,后者不返回结果。

以下是 RecursiveTask 中一些重要的方法及其含义:

  1. RecursiveTask() :构造方法,通常会通过覆盖此类的构造方法来初始化任务所需的任何状态。

  2. compute() :这是一个抽象方法,意味着当定义 RecursiveTask 时必须实现它,这个方法定义了任务的实际计算逻辑,通常,会在这个方法中决定任务是应该继续递归分解还是已经足够小,可以直接计算。

  3. fork() :这个方法是从 ForkJoinTask 继承来的,它用于在 ForkJoinPool 中异步执行当前任务,调用 fork() 会导致当前任务被安排到某个工作线程上,然后立即返回,允许调用者继续执行其他任务。

  4. join() :这也是从 ForkJoinTask 继承来的方法,它会阻塞当前线程,直到任务完成执行并返回结果,如果在一个任务中调用了另一个任务的 fork(),然后需要等待那个任务完成并获取其结果,就会使用 join()

  5. invoke() :这也是 ForkJoinTask 的一个方法,但通常不直接在 RecursiveTask 中使用,它主要用于非 ForkJoinPool 线程中启动任务,它会简单地调用 fork()(如果当前线程是 ForkJoinPool 的一部分)或直接调用 compute()(如果不是)。

  6. isCompletedAbnormally() :检查任务是否因为抛出异常而异常完成。

  7. isCancelled() :检查任务是否已经被取消。

  8. getRawResult() :获取任务的结果,但不等待任务完成,如果任务尚未完成,这可能会返回一个不完整或无效的结果。

  9. setRawResult(V) :设置任务的结果,这通常不是由应用程序代码直接调用的,而是在 compute() 方法内部,当任务完成其计算时使用。

  10. exec() :这是一个受保护的方法,通常在 ForkJoinTask 子类内部使用,用于实际执行任务,在大多数情况下,不需要直接覆盖或调用这个方法,除非正在进行一些非常特殊的扩展。

在使用RecursiveTask 时,通常需要重点关注 compute() 方法以及可能涉及任务分解和组合的逻辑,fork()join() 是在这些逻辑中最常用的方法,而其他方法更多地用于查询任务的状态或进行更高级的控制。

核心总结

【揭秘】RecursiveTask全面解析 - 程序员古德

RecursiveTask 是 Java 中专为支持可分解的并行任务设计,它的优点在于能轻松将大问题拆分成小问题,通过 ForkJoinPool 高效利用多核处理器,简化并行编程,它的缺点也很明显,比如递归分解可能引入额外开销,且不适合有状态或相互依赖的任务,在使用时,确保任务无状态且可独立执行,合理设置阈值以避免过度分解,同时考虑任务的平衡性以减少等待时间,总之RecursiveTask的优势就是处理可递归划分且无依赖的计算密集型任务。

关注我,每天学习互联网编程技术 - 程序员古德

END!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据结构-顺序表的实现 [王道]

本博客记录个人寒假学习内容。此篇博客内容为 顺序表的定义。 博客中截图来自王道数据结构公开课 目录 顺序表的定义 顺序表的特点 顺序表的实现--静态分配 顺序表的实现--动态分配 顺序表的定义--知识结构框架 顺序表的定义 >线性表是具有相同(每个数据元素所占的空间…

win11设置mysql开机自启

目录 命令式 1、打开命令提示符或 PowerShell&#xff1a; 2、使用管理员权限运行命令行工具&#xff1a; 3、设置 MySQL 服务为开机自启动&#xff1a; 4、启动 MySQL 服务&#xff1a; 5、 验证设置是否生效&#xff1a; 操作视图式 1、右击任务栏 ---> 选择任务管…

南京观海微电子---如何减少时序报告中的逻辑延迟

1. 引言 在FPGA逻辑电路设计中&#xff0c;FPGA设计能达到的最高性能往往由以下因素决定&#xff1a; ▪ 工作时钟偏移和时钟不确定性&#xff1b; ▪ 逻辑延迟&#xff1a;在一个时钟周期内信号经过的逻辑量&#xff1b; ▪ 网络或路径延迟&#xff1a;Vivado布局布线后引…

服务攻防-开发框架安全SpringBootStruts2LaravelThinkPHPCVE复现

知识点&#xff1a; 1、PHP-框架安全-Thinkphp&Laravel 2、J2EE-框架安全-SpringBoot&Struts2 章节点&#xff1a; 1、目标判断-端口扫描&组合判断&信息来源 2、安全问题-配置不当&CVE漏洞&弱口令爆破 3、复现对象-数据库&中间件&开发框架&am…

深入理解TCP网络协议(1)

目录 1.TCP协议的段格式 2.TCP原理 2.1确认应答 2.2超时重传 3.三次握手(重点) 4.四次挥手 1.TCP协议的段格式 我们先来观察一下TCP协议的段格式图解: 源/目的端口号:标识数据从哪个进程来,到哪个进程去 32位序号/32位确认号:TCP会话的每一端都包含一个32位&#xff08…

力扣hot100 每日温度 单调递减栈

Problem: 739. 每日温度 文章目录 思路复杂度&#x1f49d; 单调栈 思路 &#x1f469;‍&#x1f3eb; 参考题解 复杂度 ⏰ 时间复杂度: O ( n ) O(n) O(n) &#x1f30e; 空间复杂度: O ( n ) O(n) O(n) &#x1f49d; 单调栈 class Solution {public int[] dailyTem…

【人工智能】反向传播算法及梯度下降法

反向传播算法 反向传播算法英文简称为BP&#xff0c;其基本思想是逐一地由样本集中的样本计算出实际输出和误差测度&#xff0c;通过误差测度对权重序列进行调整&#xff0c;重复这个循环&#xff0c;直到误差降至最低。 步骤&#xff1a;用输出层的误差调整输出层权值矩阵&am…

阿里云1分钟成功搭建幻兽帕鲁服务器,Palworld开黑不卡

如何自建幻兽帕鲁服务器&#xff1f;基于阿里云服务器搭建幻兽帕鲁palworld服务器教程来了&#xff0c;一看就懂系列。本文是利用OOS中幻兽帕鲁扩展程序来一键部署幻兽帕鲁服务器&#xff0c;阿里云百科aliyunbaike.com分享官方基于阿里云服务器快速创建幻兽帕鲁服务器教程&…

C++11(中):智能指针

智能指针 1.内存泄漏1.1内存泄漏的概念以及危害1.2内存泄漏的场景1.3如何避免内存泄漏 2.智能指针的使用及原理2.1RAII2.2智能指针的原理2.3 std::auto_ptr2.4 定制删除器2.5 std::unique_ptr2.6 std::shared_ptr2.7 std::weak_ptr2.7.1 std::shared_ptr的循环引用2.7.2 循环引…

go语言(二十一)---- channel的关闭

channel不像文件一样需要经常去关闭&#xff0c;只有当你确实没有任何发送数据了&#xff0c;或者你想显示的结束range循环之类的&#xff0c;才去关闭channel。关闭channel后&#xff0c;无法向channel再发送数据&#xff0c;&#xff08;引发pannic错误后&#xff0c;导致接收…

力扣20、有效的括号(简单)

1 题目描述 图1 题目描述 2 题目解读 给定的字符串只包含括号&#xff0c;判断这个字符串中的括号是否按照正确顺序出现&#xff0c;即这个字符串是否有效。 3 解法一&#xff1a;栈 C的STL中的stack&#xff0c;在解题时非常好用。 3.1 解题思路 使用栈stk&#xff0c;并枚举…

使用 Ant Design Pro 初始化前端项目

一、使用 pro-cli 来快速的初始化脚手架 1. 打开终端&#xff0c;输入命令 # 使用 npm npm i ant-design/pro-cli -g # create 后面加要初始化的项目名称 pro create leapi-frontend 2. 报错 PS D:\code> pro create leapi-frontend pro : 无法加载文件 D:\tools\nodejs…

Java基础—面向对象OOP—18三大特性:封装、继承与多态

由于本身理解还不是很到位&#xff0c;所以写的很绕&#xff0c;后续待补充优化 1、封装&#xff08;底层&#xff09;&#xff1a;该露的露&#xff0c;该藏的藏 高内聚&#xff1a;类的内部数据操作细节自己完成&#xff0c;不允许外部干涉低耦合&#xff1a;仅暴露少量的方…

计算机二级C语言的注意事项及相应真题-6-程序填空

目录 51.将参数num按升序插入到数组xx中52.在数组中找出两科成绩之和最高的学生并返回其在数组中的下标53.删除所有串长超过k的字符串&#xff0c;输出剩下的字符串54.根据所给的一组学生的成绩&#xff0c;计算出平均成绩&#xff0c;并计算低于平均成绩的学生的平均成绩55.将…

Python算法题集_找到字符串中所有字母异位词

本文为Python算法题集之一的代码示例 题目438&#xff1a;找到字符串中所有字母异位词 说明&#xff1a;给定两个字符串 s 和 p&#xff0c;找到 s 中所有 p 的 异位词 的子串&#xff0c;返回这些子串的起始索引。不考虑答案输出的顺序。 异位词 指由相同字母重排列形成的字…

【c++】高精度算法(洛谷刷题2024)玩具谜题详解(含图解)

系列文章目录 第三题&#xff1a;玩具谜题 视频讲解&#xff1a;http://【洛谷题单 - 算法 - 高精度】https://www.bilibili.com/video/BV1Ym4y1s7BD?vd_source66a11ab493493f42b08b31246a932bbb 文章目录 目录 系列文章目录 文章目录 前言 一、题目分析以及思考 二、代码…

查询redis路径,清除redis缓存

查询redis路径 1、执行ps -ef | grep redis 命令&#xff0c;结果如下&#xff08;记住PID&#xff09; 2、执行ps -u 系统用户名&#xff0c;进一步确定进程id, 我这里的系统用户名是root&#xff0c;执行ps -u root&#xff0c;结果如下&#xff1a; 结合1的操作结果图可知…

SERVLET生命周期API

SERVLET生命周期API 在servlet的生命周期中,将发生创建Servlet上下文、创建会话、向Servlet上下文添加属性等各种事件。在servlet的生命周期内发生事件时,Web容器将通知侦听器类。要接收事件的通知,侦听器类需要扩展Servlet API的侦听器接口。 1. 事件类型 servlet生命周期…

关于如何利用ChatGPT提高编程效率的

自从去年ChatGPT3.5推出以后&#xff0c;这一年时间在编程过程中我也在慢慢熟悉人工智能的使用&#xff0c;目前来看即使是免费的ChatGPT3.5对于编程效率的提升也是有很大帮助的&#xff0c;虽然在使用过程中确实出现了一些问题&#xff0c;本文记录下我的一些心得体会和用法。…

Peter算法小课堂—二叉堆(优先队列)

课前小视频&#xff1a;(7 封私信 / 62 条消息) 看动画&#xff0c;学算法&#xff0c;C实现建立二叉堆&#xff0c;优先队列和堆排序的基础 - 知乎 (zhihu.com) 二叉堆&#xff08;优先队列&#xff09; 大家想想&#xff0c;什么数据结构能做到插入&#xff08;删除&#x…