寒假打卡14-1月29日

Java Fork/Join 框架——并行任务处理

Java Fork/Join 框架是 Java 7 引入的一种用于并行任务处理的框架。它通过递归地将大任务分解成小任务,然后并行执行这些小任务,从而充分利用多核处理器的性能。Fork/Join 框架主要由 ForkJoinPoolRecursiveTask/RecursiveAction 组成。

ForkJoinPool

ForkJoinPool 是 Fork/Join 框架的核心类,它负责管理工作线程并调度任务。ForkJoinPool 提供了一种高效的工作窃取(Work-Stealing)算法,使得空闲的工作线程可以从其他忙碌的工作线程中窃取任务来执行,从而提高并行任务的执行效率。

创建 ForkJoinPool

我们可以通过以下方式创建 ForkJoinPool

ForkJoinPool forkJoinPool = new ForkJoinPool();

或者通过指定并行度(工作线程数)来创建:

int parallelism = Runtime.getRuntime().availableProcessors();
ForkJoinPool forkJoinPool = new ForkJoinPool(parallelism);

RecursiveTask 和 RecursiveAction

RecursiveTaskRecursiveAction 是 Fork/Join 框架中的两个抽象类,分别用于有返回值和无返回值的任务。我们可以通过继承这两个抽象类来实现具体的任务逻辑,并在任务中递归地分解和合并任务。

RecursiveTask 示例

下面是一个使用 RecursiveTask 实现的求和任务示例:

import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;

public class SumTask extends RecursiveTask<Long> {
    private static final int THRESHOLD = 1000;
    private final long[] array;
    private final int start;
    private final 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) {
            return computeDirectly();
        } else {
            int mid = (start + end) / 2;
            SumTask leftTask = new SumTask(array, start, mid);
            SumTask rightTask = new SumTask(array, mid, end);
            leftTask.fork();
            long rightResult = rightTask.compute();
            long leftResult = leftTask.join();
            return leftResult + rightResult;
        }
    }

    private long computeDirectly() {
        long sum = 0;
        for (int i = start; i < end; i++) {
            sum += array[i];
        }
        return sum;
    }

    public static void main(String[] args) {
        long[] array = new long[10000];
        for (int i = 0; i < array.length; i++) {
            array[i] = i;
        }

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SumTask sumTask = new SumTask(array, 0, array.length);
        long result = forkJoinPool.invoke(sumTask);
        System.out.println("Sum: " + result);
    }
}

在上述代码中,我们定义了一个 SumTask 类继承自 RecursiveTask<Long>,并实现了 compute 方法。在 compute 方法中,我们递归地将大任务分解成小任务,直到任务的大小小于等于阈值(THRESHOLD),然后直接计算结果。

RecursiveAction 示例

下面是一个使用 RecursiveAction 实现的数组排序任务示例:

import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
import java.util.Arrays;

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

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

    @Override
    protected void compute() {
        if (end - start <= THRESHOLD) {
            Arrays.sort(array, start, end);
        } else {
            int mid = (start + end) / 2;
            SortTask leftTask = new SortTask(array, start, mid);
            SortTask rightTask = new SortTask(array, mid, end);
            invokeAll(leftTask, rightTask);
        }
    }

    public static void main(String[] args) {
        int[] array = new int[10000];
        for (int i = 0; i < array.length; i++) {
            array[i] = (int) (Math.random() * 10000);
        }

        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SortTask sortTask = new SortTask(array, 0, array.length);
        forkJoinPool.invoke(sortTask);
        System.out.println("Sorted array: " + Arrays.toString(array));
    }
}

在上述代码中,我们定义了一个 SortTask 类继承自 RecursiveAction,并实现了 compute 方法。在 compute 方法中,我们递归地将大任务分解成小任务,直到任务的大小小于等于阈值(THRESHOLD),然后直接对数组进行排序。

Fork/Join 框架的优缺点

优点

  • 高并发性能:通过工作窃取算法提高并行任务的执行效率。
  • 简化并行编程:提供了简单的 API 来实现并行任务的分解和合并。

缺点

  • 内存开销大:递归地创建大量任务,可能会增加内存开销。
  • 适用场景有限:适用于 CPU 密集型任务,对于 I/O 密集型任务效果不佳。

总结

Java Fork/Join 框架是一种高效的并行任务处理框架,通过递归地将大任务分解成小任务,并行执行这些小任务,从而充分利用多核处理器的性能。ForkJoinPoolRecursiveTask/RecursiveAction 是框架的核心类,提供了简单的 API 来实现并行任务的分解和合并。

希望通过本篇文章,大家对 Java Fork/Join 框架有了更深入的了解。在接下来的文章中,我们将继续探讨更多关于 Java 并发编程的知识点,敬请期待!

posted @ 2024-12-29 09:10  aallofitisst  阅读(11)  评论(0)    收藏  举报