Java中的Fork/Join框架

什么是Fork/Join框架?

Fork/Join框架是Java 7引入的一种并行计算框架,位于java.util.concurrent包中,旨在帮助开发者分治复杂任务,充分利用多核处理器的并行能力。通过“分而治之”的策略,将大任务拆分成若干小任务(Fork),再将结果合并(Join),以实现更高效的计算。

适用场景

Fork/Join框架特别适用于以下场景:

  • 递归任务:可以将任务不断拆分成子任务,并行执行。
  • 大数据计算:如数组求和、排序等需要分段处理的任务。
  • 分治策略:适合问题规模大,且能够分割成多个独立子问题的场景。

Fork/Join框架的核心概念

  • Fork:将任务分解成多个子任务,并将子任务提交到线程池执行。
  • Join:等待所有子任务完成,并合并结果。
  • ForkJoinTask:代表可分解的任务,是Fork/Join框架的核心抽象类。
  • RecursiveTask:继承自ForkJoinTask,表示有返回结果的任务。
  • RecursiveAction:继承自ForkJoinTask,表示无返回结果的任务。

代码示例:使用Fork/Join框架求和

下面通过一个示例来讲解如何使用Fork/Join框架计算数组的元素之和。

1. 创建任务类

创建一个继承自RecursiveTask的任务类SumTask,用于将大数组分割成小数组,并行计算每个小数组的和。

import java.util.concurrent.RecursiveTask;

public class SumTask extends RecursiveTask<Long> {
    private static final int THRESHOLD = 1000; // 阈值
    private long[] array;  // 数组
    private int start;     // 起始索引
    private int end;       // 结束索引

    public SumTask(long[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @Override
    protected Long compute() {
        // 当任务足够小的时候,直接计算
        if (end - start <= THRESHOLD) {
            long sum = 0;
            for (int i = start; i < end; i++) {
                sum += array[i];
            }
            return sum;
        } else {
            // 将任务一分为二
            int middle = (start + end) / 2;
            SumTask leftTask = new SumTask(array, start, middle);
            SumTask rightTask = new SumTask(array, middle, end);

            leftTask.fork();  // 异步执行子任务
            long rightResult = rightTask.compute(); // 计算右侧子任务
            long leftResult = leftTask.join(); // 等待左侧子任务完成并获取结果

            return leftResult + rightResult; // 合并结果
        }
    }
}

2. 执行Fork/Join任务

在主类中,使用ForkJoinPool来提交任务,并获取最终的计算结果。

import java.util.concurrent.ForkJoinPool;

public class Main {
    public static void main(String[] args) {
        // 创建随机数组
        long[] array = new long[5000];
        for (int i = 0; i < array.length; i++) {
            array[i] = i + 1;
        }

        // 创建ForkJoinPool
        ForkJoinPool pool = new ForkJoinPool();

        // 提交SumTask
        SumTask task = new SumTask(array, 0, array.length);
        Long result = pool.invoke(task);

        System.out.println("Sum: " + result);
    }
}

输出结果:

Sum: 12502500

通过Fork/Join框架,程序能够充分利用多核处理器的能力,并行执行分割的任务,从而在大数据场景下显著提升计算效率。

Fork/Join与普通线程池的对比

  • 更高效的任务分解:普通线程池通常是将任务提交到一个线程执行,而Fork/Join能够将大任务不断拆分成更小的子任务,并在多个核心上并行执行。
  • 工作窃取算法(Work-Stealing):Fork/Join框架使用工作窃取算法,如果某个线程完成了自己的任务,会主动从其他线程的队列中窃取任务来执行,从而保持所有线程的高效运转。

使用RecursiveAction执行无返回值任务

在某些场景下,我们可能只需要执行一些操作,而不需要返回结果。此时可以使用RecursiveAction来代替RecursiveTask。

例如,我们可以使用RecursiveAction来将数组中的所有元素加1:

import java.util.concurrent.RecursiveAction;

public class IncrementTask extends RecursiveAction {
    private static final int THRESHOLD = 1000;
    private long[] array;
    private int start;
    private int end;

    public IncrementTask(long[] array, int start, int end) {
        this.array = array;
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        if (end - start <= THRESHOLD) {
            for (int i = start; i < end; i++) {
                array[i]++;
            }
        } else {
            int middle = (start + end) / 2;
            IncrementTask leftTask = new IncrementTask(array, start, middle);
            IncrementTask rightTask = new IncrementTask(array, middle, end);

            invokeAll(leftTask, rightTask);
        }
    }
}

有兴趣的小伙伴可以关注我的公众号【知识星球站】一起讨论学习!!
在这里插入图片描述

无人助我凌云志,我自扶摇上九天。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霜!!

不错,👆赏!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值