java之ForkJoinPool 底层原理

161 阅读2分钟

ForkJoinPool 底层原理

1. 工作窃取算法(Work-Stealing)

  • 每个工作线程维护自己的双端队列(Deque)
  • 线程优先处理自己队列中的任务(LIFO顺序)
  • 当自身队列为空时,从其他线程队列尾部窃取任务(FIFO顺序)
  • 优势:减少线程竞争,最大化CPU利用率

2. 任务分割机制

graph TD
A[初始任务] --> B{是否达到阈值?}
B -->|是| C[直接计算结果]
B -->|否| D[分割为子任务]
D --> E[fork子任务]
E --> F[join等待结果]
F --> G[合并结果]

3. 关键组件

  • ForkJoinWorkerThread:特殊的工作线程
  • WorkQueue:内部使用的双端队列
  • RecursiveTask:有返回值的任务
  • RecursiveAction:无返回值的任务

4. 执行流程

  1. 提交任务到公共队列
  2. 工作线程从自己队列头部获取任务
  3. 任务分割(fork)时,新任务压入线程自身队列
  4. 结果收集(join)时,递归处理子任务
  5. 空闲线程窃取其他队列尾部任务

底层原理:

ForkJoinPool是ExecutorService的一个实现,专为分治算法设计。它使用工作窃取算法,每个工作线程都有自己的工作队列,这些队列是双端队列(deque)。

当线程执行自己生成的任务(通过fork)时,它会将任务推入自己的队列头部,并从头部取出任务执行(LIFO)。

当线程自己的队列为空时,它会尝试从其他线程的队列尾部窃取任务(FIFO)。这种方式减少了线程间的竞争,提高了并行性能。

在Java中的应用:

并行流(Parallel Streams)

// 底层使用ForkJoinPool.commonPool()
long sum = IntStream.range(1, 100_000)
                   .parallel()
                   .sum();

CompletableFuture

CompletableFuture.supplyAsync(() -> {
    // 默认使用ForkJoinPool
    return intensiveComputation();
});

Arrays.parallelSort()

int[] bigArray = new int[10_000_000];
Arrays.parallelSort(bigArray);  // 使用Fork/Join框架

Concurrent Collections

ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.forEachValue(1, value -> process(value));  // 并行遍历

ForkJoinPool 实例代码

以下是一个使用 ForkJoinPool 计算斐波那契数列的示例:

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

public class ForkJoinDemo extends RecursiveTask<Long> {

    private final long n;

    public ForkJoinDemo(long n) {
        this.n = n;
    }

    @Override
    protected Long compute() {
        // 阈值设置:小于等于20直接计算
        if (n <= 20) {
            return calculateDirectly(n);
        }
        
        // 分治策略:拆解任务
        ForkJoinDemo task1 = new ForkJoinDemo(n - 1);
        ForkJoinDemo task2 = new ForkJoinDemo(n - 2);
        
        // 异步执行子任务(fork)
        task1.fork();
        task2.fork();
        
        // 合并结果(join)
        return task1.join() + task2.join();
    }

    private long calculateDirectly(long n) {
        if (n <= 1) return n;
        long a = 0, b = 1;
        for (long i = 2; i <= n; i++) {
            long next = a + b;
            a = b;
            b = next;
        }
        return b;
    }

    public static void main(String[] args) {
        // 创建ForkJoinPool(默认使用所有可用处理器)
        ForkJoinPool pool = new ForkJoinPool();
        
        // 提交任务并获取结果
        long result = pool.invoke(new ForkJoinDemo(30));
        
        System.out.println("斐波那契(30) = " + result);  // 输出:832040
        pool.shutdown();
    }
}