欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ForkJoinPool的使用

程序员文章站 2022-03-08 22:36:52
...

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

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

ForkJoinPool的使用

下面是一个小例子:

 

    //初始化一个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;
            }
        }
    }

执行逻辑:

第一步:

ForkJoinPool的使用

第二步:

ForkJoinPool的使用 

 第三步:

ForkJoinPool的使用 

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

相关标签: 多线程