狐言不胡言

导航

ForkJoinPool的工作原理和使用

       场景:当任务很多,成千上万个,或者单个任务很大,执行起来很耗时间,这时,就可以把任务进行拆分,拆分成多个小任务去执行,然后小任务执行完毕后再把每个小任务执行的结果合并起来,这样就可以节省时间。

        ForkJoinPool实现了ExecutorService接口,所以它也是一种线程池,做的工作就是,把一个任务拆分成若干个小任务执行,然后再把小任务执行的结果汇总。

下面是一个小例子:

 

    //初始化一个ForkJoinPool
    static ForkJoinPool pool = new ForkJoinPool(3,
            ForkJoinPool.defaultForkJoinWorkerThreadFactory,
            null,
            true);

    //一个集合,模拟网站
    static ArrayList<String> list = new ArrayList<>();
    //集合中的数据
    static void addList() {
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
        list.add("www.baidu.com");
        list.add("www.blog.csdn.net");
    }


    public static void main(String[] args) throws ExecutionException, InterruptedException {
        addList();
        //提交任务
        ForkJoinTask<String> task =  pool.submit(new Work(list, 0, list.size()));
        System.out.println(task.get());


    }

    //模拟请求
    public static String doRequest(String url, int index) {
        return index + "--》请求测试:" + url + "\n";
    }

    //需要继承RecursiveTask,来实现自己的拆分逻辑
    static class Work extends RecursiveTask<String> {
        List<String> list;
        int start;
        int end;

        public Work(List<String> list, int start, int end) {
            this.list = list;
            this.start = start;
            this.end = end;
        }

        @Override
        protected String compute() {
            int count = end - start;
            String result = "";
            //当任务小于10个时直接执行,否则就拆分
            if (count <= 10) {
                for (int i = 0; i<list.size(); i++) {
                    result += doRequest(list.get(i), i);
                }
                return result;
            } else {
                //获取任务数量索引的中间值
                int x = (start + end) / 2;
                //拆分任务
                Work work1 = new Work(list, start, x);
                work1.fork();
                //拆分任务
                Work work2 = new Work(list, x, end);
                work2.fork();
                //获取任务执行结果
                result += work1.join();
                result += work2.join();
                return result;
            }
        }
    }

执行逻辑:

第一步:

第二步:

 第三步:

每一个线程有任务后,都会去拆分任务,当拆分的小任务满足执行条件后,就会去执行,然后按照层级,从拆分后最小的层级执行完任务,一层层向上回收任务结果,最后到ForkJoinTask中,然后就可以获取到每一个小任务执行的结果。

posted on 2021-04-17 09:31  狐言不胡言  阅读(1980)  评论(0编辑  收藏  举报