ForkJoinPool

2020-11-11  本文已影响0人  From64KB

ForkJoinPool是什么?和ExectuorService有什么差异?
ExectuorService相同的点在于,可以驱动并完成多个提交任务。特点如下:

  1. ForkJoinPool 适用于提交会产生子任务的任务。文字上似乎很难理解这是什么含义。看下面的图片:
    image.png

这个提交的task本身会产生很多个子task(sub-task),那么这样的场景就是和使用ForkJoinPooltask会产生很多子task(sub-task),如果都在一个线程上完成的话,那么cpu将不能得到有效利用(为什么?参见这里关于CPU-线程模型的一些知识点)。说了这些还是感觉很抽象,那么有没有具体的例子可以作为理解什么样的task会产生多个子task(sub-task)呢?斐波那契数列(Fibonacci Sequence)。除了第一个和第二个数,每一个斐波那契数都可以被拆成前两个数的和。那么这样就可以将某个斐波那契数拆成前两个斐波那契数和的task。可以参考把原来需要递归调用的方法,放到多个线程去执行。

如果还是不明白没,希望下面这张图能帮你理解ForkJoinPool 对于task本身会产生很多个子task(sub-task)这一概念。

ForkJoinPool.png
  1. Per-Thread queueing & Working-Stealing 线程的任务队列和工作任务协同分担。最接近的翻译应该是: 线程对应的任务队列和工作任务盗取,显然这样翻译对于理解概念并没有什么额外帮助(当然第一种翻译也没有什么理解上的帮助...my poor English)。
    还是通过举例子来理解这一概念吧。假设有一个两个线程的线程池,向里面提交了很多task:
    image.png
    这两个线程本身就各自有一个deque (双端队列:double-ended queue)用于存储某个task fork出来的多个子task(并不会存储到上面的common queue)中:
    fork-task.png

这样做有什么好处呢?

那这样做有没有什么问题呢?

综上,ForkJoinPoolExectuorService有什么差异?相同点都是用于异步并发执行任务,不同点在于ForkJoinPool的每个线程都有自己的 task deque用于存储某个task fork出来的子task。并且为了提高线程的利用率,ForkJoinPool各个线程之间存在子task协同完成这一概念,空闲的线程会通过获取其他线程deque尾部的子task协助完成任务。

既然说的这么好,那怎么样使用呢? api和ExectuorService差别不大。但是需要关注submit(ForkJoinTask<T> task)、invoke(ForkJoinTask<T> task) 和 execute(ForkJoinTask<?> task)。还是拿上面斐波那契数列(Fibonacci Sequence)的例子:

        ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
        Integer invoke = forkJoinPool.invoke(new Fibonacci(10));

    static class Fibonacci extends RecursiveTask<Integer> {

        private int n;

        public Fibonacci(int n) {
            this.n = n;
        }

        @Override
        protected Integer compute() {
            if (n <= 1) {
                return n;
            }

            Fibonacci fibonacci = new Fibonacci(n - 1);
            fibonacci.fork();//注意,fork出新的task
            Fibonacci fibonacci1 = new Fibonacci(n - 2);
            fibonacci1.fork();//注意,fork出新的task

            return fibonacci.join() + fibonacci1.join();//join获取结果
        }
    }

也很简单,那么ForkJoinPool使用有什么注意点呢?

不难看出ForkJoinPool适用于CPU敏感型的操作需求,注重执行效率。

上一篇下一篇

猜你喜欢

热点阅读