深入浅出:手把手实现简易版ForkJoinPool并解读背后的并行计算原理

ForkJoinPool的原理解析

ForkJoinPool 是 Java 并行计算框架中的核心类,用于执行大量小任务的递归分解。它基于工作窃取(Work-Stealing) 算法,允许线程池中的空闲线程从其他忙碌线程的双端队列中“窃取”任务,从而高效利用 CPU 核心。这个机制提高了任务执行的并行性和性能。

ForkJoinPool工作流程:
  1. 任务分解(Fork):大任务被递归拆分为多个子任务。
  2. 任务合并(Join):子任务的结果逐步合并为最终结果。
  3. 工作窃取(Work-Stealing):当线程完成自己队列中的任务时,尝试从其他线程的队列中窃取尚未完成的任务,确保线程利用率最大化。
实现简易版ForkJoinPool
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;

// 任务类,继承RecursiveTask,表示有返回值的任务
class SimpleTask extends RecursiveTask<Integer> {
    
    
    private int start;
    private int end;
    private static final int THRESHOLD = 10; // 临界值

    public SimpleTask(int start, int end) {
    
    
        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 += i;
            }
            return sum;
        } else {
    
    
            // 否则,分裂成两个子任务
            int middle = (start + end) / 2;
            SimpleTask leftTask = new SimpleTask(start, middle);
            SimpleTask rightTask = new SimpleTask(middle + 1, end);

            // 并行执行两个子任务
            leftTask.fork();
            int rightResult = rightTask.compute();
            int leftResult = leftTask.join();

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

public class ForkJoinPoolExample {
    
    
    public static void main(String[] args) {
    
    
        ForkJoinPool pool = new ForkJoinPool(); // 创建ForkJoinPool

        SimpleTask task = new SimpleTask(1, 100); // 创建任务

        // 提交任务并获取结果
        int result = pool.invoke(task);
        System.out.println("Sum: " + result);
    }
}
代码解释:
  • SimpleTask:定义了一个递归任务,通过fork()方法分解任务,并通过join()合并结果。
  • ForkJoinPool:用于并行执行任务,当任务规模超过阈值时,递归地分裂任务。

这种简化版的 ForkJoinPool 展示了核心的任务分解、任务合并以及如何高效地进行并行处理。