【揭秘】RecursiveTask全面解析

内容概要

RecursiveTask的优点在于能够将复杂使命递归分化为更小的子使命,然后提高处理效率,经过ForkJoinPool履行,RecursiveTask能充分运用多核处理器资源,完结使命的并行化处理,大大加快了核算速度,此外,它还简化了并行编程的复杂性,使开发者能够更专心于业务逻辑的完结。

官方文档:docx.iamqiang.com/jdk11/api/j…

中心概念

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的优势便是处理可递归区分且无依靠的核算密集型使命。

【揭秘】RecursiveTask全面解析

END!