【java】Fork/Join框架

记录下get到的新东西——java的Fork/Join框架。
1、什么是Fork/Join框架?
Fork/Join框架是java 7提供的一个用于并行执行任务的框架,主要用于将一个比较大的任务分割成若干个小任务,最终再把分割后的任务结果汇总起来,最后得到最终结果的一个框架。
其中:Fork就是把一个大任务切分为若干子任务的执行,Join就是合并这些子任务的执行结果,最后得到这个大任务的结果。
比如:筛选10000张符合某种条件的图片,可以切分成100个子任务,每个子任务分别对100张图片进行筛选,最后汇总这100个子任务的结果得到最终结果。

因此,使用Fork/Join框架主要分为两个步骤:1、分割任务;2、执行任务并合并结果。

2、Fork/Join框架使用两个类来完成上面两件事。
1)ForkJoinTask:我们要使用ForkJoin框架,则就需要先创建一个ForkJoin任务。他提供在任务中执行fork()和join()操作的机制。通常情况下,我们不需要直接继承ForkJoinTask类,而是直接继承子类:

  1. RecursiveAction:不需要返回结果的任务
  2. RecursiveTask:有返回值的任务

2)ForkJoinPool:ForkJoinTask需要通过ForkJoinPool才可以执行。
【任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务】

下面用数字连加做个demo
1、创建一个类,继承RecursiveTask。

/**
 * 累计加法任务类,例如:从1加到100。
 */
class CountTask extends RecursiveTask<Integer> {
    // 一个任务最小的加法个数:4
    private static final int THRESHOLD = 4;
    private int start;// 加数的起始值
    private int end;// 加数的结束值.例如:从4加到14,start就是4,end就是14

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

    @Override
    protected Integer compute() {
        int sum = 0;
        // 判断任务是否可以被向下拆分(加的个数是否超过了阈值)
        boolean canCompute = (start - end) > THRESHOLD;
        if (canCompute) {// 超过了阈值拆分成两个子任务
            int middle = (start + end) / 2;//获取中间值
            // 从中间值为分割点,分派给两个子任务(子任务还会自己判断是否应该再拆分,依次递归)
            CountTask leftTask = new CountTask(start, middle);
            CountTask rightTask = new CountTask(middle + 1, end);
            // fork两个任务
            leftTask.fork();
            rightTask.fork();
            // 获取任务执行完毕后的结果
            int left = leftTask.join();
            int right = rightTask.join();
            // 将子任务的结果相加
            sum = left + right;
        } else {// 如果没有超过阈值,直接连加即可
            for (int i = start; i <= end; i++) {
                sum += i;
            }
        }
        return sum;
    }

2、通过ForkJoinPool执行任务

public class ForkJoin {

    public static void main(String[] args) {
    // 创建任务,从1到100连加
        CountTask task = new CountTask(1,100);
        // 创建ForkJoinPool 用于执行任务
        ForkJoinPool pool = new ForkJoinPool();
        // 执行任务
        Future<Integer> result = pool.submit(task);
        try {
        // 打印执行的结果(5050)
            System.out.println(result.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

说在后面的话:
异常处理,如果ForkJoinTask在执行的时候可能会抛出异常,但是,我们没办法在主线程里直接捕获异常,所以,ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException()方法获取异常。

ForkJoinPool pool = new ForkJoinPool();
CountTask task = new CountTask(1,100);
Future<Integer> result = pool.submit(task);
// 判断是否异常终止
if(task.isCompletedAbnormally()){
// 打印异常信息
    System.out.println(task.getException());
}

猜你喜欢

转载自blog.csdn.net/lantingshuxu/article/details/80514838