Java类ForkJoin的详解

在古代,皇帝要想办成一件事情,肯定不会亲自动手,而是任务细分给下面的大臣。下面的大臣也懒,于是把任务继续分给几个部分,继续下发,于是到了最后负责的人手里就完成一个小功能。上面的领导再把这些结果一层一层汇总。最终返回给皇帝,这就是分而制之的思想,也是我们今天的主题ForkJoin。

一、简介

从JDK1.7开始,Java就提供ForkJoin框架用于并执行任务,它的思想就是一个大任务分割成小任务,最终汇总每个小任务的结果的到大任务的结果。

1、ForkJoinPool

既然任务是被逐步细化的,那就需要把这些任务存在一个池子里面。这个池子就是ForkJoinPool,它与其他的ExecutorService区别主要在于区别主要在于它使用“工作窃取”,那么什么是“工作窃取呢”?

一个大任务被划分成无数个小任务,这些任务被分配到不同的队列,这些队列有些干活干的快,有些干活慢,于是干的快的,一看自己没任务需要执行了,就去隔壁的队列里面拿去任务执行。

2、ForkJoinTask

ForkJoinTask就是ForkJoinPool里面的每一个任务,他主要有两个子类:

RecursiveAction和RecursiveTask,然后通过fork()方法去分配任务执行任务,通过Join方法汇总任务结果。

这就整个过程的运用,他有两个子类,使用这两个子类都可以实现我们的任务分配和计算。

(1) RecursiveAction 一个递归无结果的ForkJoinTask(没有返回值)

扫描二维码关注公众号,回复: 10138415 查看本文章

(2) RecursiveTask 一个递归有结果的ForkJoinTask(有返回值)

ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责存放程序提交给ForkJoinPool的任务,而ForkJoinWorkThread数组负责执行这行这些任务。

下面我们看看如何使用ForkJoin框架。

二、使用

1、RecursiveTask:有返回结果

(1)第一步:创建类MyRecursiveTask 继承RecursiveAction:

public class MyRecursiveTask extends RecursiveTask<Integer> {

    private final static int threshold = 3;
    private final int start;
    private final int end;

    public MyRecursiveTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        //如果任务分到不能再细分,那就直接计算
        if (end - start <= threshold) {
            return IntStream.rangeClosed(start, end).sum();
        } else {
            int mid = (start + end) / 2;
            MyRecursiveTask leftTask = new MyRecursiveTask(start, mid);
            MyRecursiveTask rightTask = new MyRecursiveTask(mid, end);
            leftTask.fork();
            rightTask.fork();
            return leftTask.join() + rightTask.join();
        }
    }
}

(2)第二步:创建ForkJoinTest测试类:

public class ForkJoinTest {

    public static void main(String[] args) {
        try {
            final ForkJoinPool pool =new ForkJoinPool();
            ForkJoinTask<Integer> result= pool.submit(new MyRecursiveTask(0,100));
            System.out.println("result = [" + result.get() + "]");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

2、RecursiveAction:无返回结果

(1)第一步:创建MyRecursiveAction继承RecursiveAction;


public class MyRecursiveAction extends RecursiveAction {

    private final static int threshold = 3;
    public  static final AtomicInteger sum = new AtomicInteger(0);
    private final int start;
    private final int end;


    public MyRecursiveAction(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected void compute() {
        //如果任务拆分到不能再细分,那就计算
        if (end - start <= threshold) {
            sum.addAndGet(IntStream.rangeClosed(start, end).sum());
        }else {
            int mid = (start+end)/2;
            MyRecursiveAction  leftTask = new MyRecursiveAction(start,mid);
            MyRecursiveAction rightTask = new MyRecursiveAction(mid,end);
            leftTask.fork();
            rightTask.fork();
        }
    }
}

(2)第二步:创建ForkJoinTest测试类:

public class ForkJoinTest {

    public static void main(String[] args) {
        try {
            final ForkJoinPool pool = new ForkJoinPool();
            pool.submit(new MyRecursiveAction(0, 100));
            pool.awaitTermination(3, TimeUnit.SECONDS);
            System.out.println("sum=" + MyRecursiveAction.sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
发布了21 篇原创文章 · 获赞 4 · 访问量 508

猜你喜欢

转载自blog.csdn.net/weixin_39617728/article/details/104932513