Fork/Join

java.util.concurrent.ForkJoinPool 由 Java 大师 Doug Lea 主持编写,它可以将一个大的任务拆分成多个子任务进行并行处理,最后将子任务结果合并成最后的计算结果,并进行输出。

我的例子

假设我们要计算数组 1 到 100 的和,不使用 fork/join 方法的话

public class Sum {

    private static int MAX = 100;

    public static void main(String[] args) {

        int[] data = new int[MAX];

        for (int i=0; i<MAX; i++) {
            data[i] = i;
        }

        long start = System.currentTimeMillis();

        long sum = 0;
        for (int i=0; i<MAX; i++) {
            sum += data[i];
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

//        System.out.println(sum);
        System.out.println(System.currentTimeMillis() - start);
    }
}

输出,这里是用的时间(ms)

1112

使用 fork/join 将 100 个数,拆成 50 对,分别求和,然后汇总结果

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.RecursiveTask;

public class IntSum extends RecursiveTask<Long> {

    private final int data[];

    public IntSum(int data[]) {
        this.data = data;
    }

    @Override
    protected Long compute() {
        long result = 0;

        int len = data.length;

        if (len < 1) {
            return 0L;
        }

        if (len < 2) {
            return (long) data[0];
        }

        if (len == 2) {
            return sum(data[0], data[1]);
        }

        List<RecursiveTask<Long>> forks = new ArrayList<>();
        for (int i=0; i<data.length; i=i+2) {
            IntSum subTask = new IntSum(new int[]{i, i+1});
            forks.add(subTask);
            subTask.fork();
        }

        for (RecursiveTask<Long> subTask : forks) {
            result = result + subTask.join();
        }

        return result;
    }

    public long sum(int a, int b) {
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return a + b;
    }
}

import java.util.concurrent.ForkJoinPool;

public class ForkJoinTest {

    private static int MAX = 100;

    public static void main(String[] args) {

        int[] data = new int[MAX];

        for (int i=0; i<MAX; i++) {
            data[i] = i;
        }

        long start = System.currentTimeMillis();

        // Create a ForkJoinPool to run the task
        ForkJoinPool pool = new ForkJoinPool();

        // Create an instance of the task
        IntSum task = new IntSum(data);

        // Run the task
        long sum = pool.invoke(task);

//        System.out.println("Sum is " + sum);

        System.out.println(System.currentTimeMillis() - start);
    }
}

输出,这里是用的时间(ms)

203

思考

  1. fork/join 方法是将一个大的任务拆成很多的小任务来做,可以递归(比如归并排序算法),也可以不用递归(这里就没有用递归)
  2. 本例中的等待 10ms 方法如果去掉,则单线程求和更快,因为它不需要创建线程,所以如果子任务的时间小于计算机创建线程的时间,那么可能单线程更快
  3. 更深入的学习需要看 java 源代码

参考

java language features,2nd


↙↙↙阅读原文可查看相关链接,并与作者交流