ForkJoin实现分而治之

2,021 阅读2分钟
  • 对于简单的并行任务可以通过"线程池+Future"方案来解决。
  • 如果任务额之间有聚合关系(AND聚合或者OR聚合)用CompletableFuture解决。
  • 批量的并行任务用CompletionService解决。

并发编程可以分为三个层面的问题: 分工,协作,互斥。

ForkJoin有什么用

Fork/Join是一个并行计算的框架,主要就是用来支持分治任务模型的,这个计算框架里的Fork对应的是分治任务模型里的任务分解,Join对应的是结果合并。

什么是分治

把一个复杂的问题分解成多个相似的子问题,然后把子问题分解成更小的子问题,知道子问题简单到可以直接求解。

算法领域有分治算法(归并排序、快速排序都属于分治算法,二 分法查找也是一种分治算法);大数MapReduce也是。

分治模型

分治任务可以分成两个阶段:任务分解,结果合并。

Fork/Join的使用

Fork/Join计算框架主要包含两部分,一部分是分治任务的线程池ForkJoinPool,另一部分是分治任务ForkJoinTask。这两部分的关系类似ThreadPoolExecutor和 Runnable的关系,都可以理解为提交任务到线程池,只不过分治任务有自己独特类型ForkJoinTask。

ForkJoinTask

  • ForkJoinTask是一个抽象类最核心的是fork()方法和join()方法,fork()会异步地执行一个子任务,join()会阻塞当前线程来等待子任务的执行结果。
  • ForkJoinTask有连个子类:
    • RecursiveAction:用递归的方式来处理分治任务,compute()方法没有返回值。
    • RecursiveTask:用递归的方式来处理分治任务,compute()方法有返回值。

使用ForkJoinTask实现计算斐波那契数列

package com.thread;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

/**
 * 实现斐波那契数列
 * 求出第n个斐波那契数列值
 **/
public class ForkJoinDemo {
    public static void main(String[] args) {
        //创建分治任务线程池
        ForkJoinPool fjp = new ForkJoinPool(4);
        //创建分治任务
        Fibonacci fib = new Fibonacci(4);
        //启动分治任务
        Integer result = fjp.invoke(fib);
        //输出结果
        System.out.println(result);
    }
    static class Fibonacci extends RecursiveTask<Integer>{
        final int n;
        public Fibonacci(int n){
            this.n = n;
        }
        @Override
        protected Integer compute() {
            if (n <= 1){
                return  n;
            }
            Fibonacci f1 = new Fibonacci(n-1);
            //创建⼦任务
            f1.fork();
            Fibonacci f2 = new Fibonacci(n-2);
            //等待子任务结果,并合并结果.
            return f2.compute() + f1.join();
        }
    }
}

ForkJoinPool与ForkJoinTask关系类似ThreadPoolExecutor和Runnable的关系。

ForkJoinPool有窃取队列的性质,空闲队列会窃取忙队列的任务

建议用不同的ForkJoinPool执行不同类型的计算任务

码字不易如果对你有帮助请给个关注

爱技术爱生活 QQ群: 894109590