多线程之ForkJoin/ForkJoinPool

1,261 阅读2分钟

ForkJoinPool简述

ForkJoinPool不是ExecutorService的替代,而是对其的补充 Java Tip: When to use ForkJoinPool vs ExecutorService;ForkJoinPool 最适合的是计算密集型的任务,如果存在I/O,线程间同步,sleep() 等会造成线程长时间阻塞的情况时,最好配合使用ManagedBlocker;Work-Stealing 的适用场景是不同的任务的耗时相差比较大,即某些任务需要运行较长时间,而某些任务会很快的运行完成,这种情况下用 Work-Stealing 很合适;但是如果任务的耗时很平均,则此时 Work-Stealing 并不适合,因为窃取任务时不同线程需要抢占锁;ForkJoinPool是分而治之的思想的体现。

使用

  • 对于要返回结果的情况,直接继承 RecursiveTask
  • 对于无需返回结果的情况,直接继承 RecursiveAction

invoke是阻塞的,带有返回值的:

submit是非阻塞、带有返回值的:
execute是非阻塞,不带返回值的:

使用ForkJoinPool计算求和示例

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

public class SumTask extends RecursiveTask<Integer> {

    private int THREHOLD = 10;
    private int[] src;
    private Integer left;
    private Integer right;

    public SumTask(int[] src, Integer left, Integer right) {
        this.src = src;
        this.left = left;
        this.right = right;
    }

    @Override
    protected Integer compute() {

        if ((right - left) < THREHOLD) {
            Integer sum = 0;
            System.out.println(left + " to " + right);
            for (int i = left; i <= right; i++)
                sum += src[i];
            return sum;
        }
        //拆分数组
        Integer mid = (left + right) >> 1;
        SumTask leftTask = new SumTask(src, left, mid);
        SumTask rightTask = new SumTask(src, mid + 1, right);
        invokeAll(leftTask, rightTask);
        return leftTask.join() + rightTask.join();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //生成随机数组
        int[] a = ArrayUtils.makeArray(45);
//        System.out.println("单线程执行结果: " + ArrayUtils.sum(a));
        ForkJoinPool forkJoinPool = new ForkJoinPool();
        SumTask task = new SumTask(a, 0, a.length - 1);
        //提交任务
        ForkJoinTask<Integer> result = forkJoinPool.submit(task);
        System.out.println("fork.join执行结果: " + result.get());
    }
}

执行结果如下

参考文章