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中,然後就可以獲取到每一個小任務執行的結果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章