通用技术 学习 java 多线程之 fork/join 基本用法

bauul · 2018年03月05日 · 最后由 bauul 回复于 2018年03月06日 · 2168 次阅读

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

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 8 条回复 时间 点赞

给陈总点赞,研究底层越来越多啦,直接做开发好了

—— 来自 TesterHome 官方 安卓客户端

CC 回复

胡总早,我这都是基础,离开发还远☺

最近的体悟,从工程角度看:架构能力,解耦、重构的能力比这些术的东西要更重要。
如果有兴趣,可以看看代码简洁之道,重构,设计模式相关的书。。。。

嗯嗯,谢谢杨总指点,还是要往深度走

没考虑 mapreduce 么。。

Nisir 回复

嗯,目前还没学习这部分

bauul 回复

楼主说的这个就是分布式计算的基本思路 推荐看看 MapReduce

Nisir 回复

感谢推荐,上半年工作计划在搭建测试平台上,下半年计划看看这部分☺

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册