被遗忘的凉白开
文章22
标签34
分类3
群经平议·周官二:分而治之,线程工具类Fork-Join的使用

群经平议·周官二:分而治之,线程工具类Fork-Join的使用

ForkJoin也是使用了分而治之的思想,在业务开发中使用的也是比较多的,我们通过图示和代码讲解了ForkJoin如何使用,怎么使用,如果对XDM有用的话,来个三连!

这是我参与更文挑战的第12天,活动详情查看: 更文挑战

这篇文章主要介绍ForkJoin的使用和原理,主要是运用了分而治之的思想

群经平议·周官二:分而治之,并归排序

1、Fork-Join原理

Fork/Join的原理就是在必要的情况下,将一个大任务进行fork拆分成若干个小任务(拆到不可再拆时),在将一个个的小任务运算结果进行join汇总,只不过ForkJoin在底层用的是多线程进行的拆分和汇总

image.png

工作密取
Fork完之后各个线程取得了各自的任务列表,但是有的线程可能干的表较快,它就会偷偷的去别的线程的任务队列里,偷偷的取出来去执行,执行完再把结果放回原来的地方,这就是工作密取

image.png

2、Fork-Join使用的标准范式

  1. pool=new ForkJoinPool()
  2. myTask=new ForkJoinTask()
  3. pool.invoke(myTask)
  4. 获取result=myTask.join

而在我们自己的任务中,有一个compute方法,在这个方法中

判断这个任务是否满足我们的条件(要不要被拆分),如果满足,就去做我们的这个任务,做完之后将结果交给上一级的mytask,这相当于一个递归,如果不满足我们的条件,将我们的任务拆分为两个或者多个Task,把我们分成的多个任务 invokeall,然后所有的子任务就会再次判断是否满足条件,满足 join吧结果返回给上一级task,不满足就再次拆分

image.png

3、Fork-Join实现整形数组中所有元素的和

public class SumArray {
    private static class SumTask extends RecursiveTask<Integer>{

        /*阈值*/
        private final static int THRESHOLD = MakeArray.ARRAY_LENGTH/10;
        private int[] src;
        private int fromIndex;
        private int toIndex;

        public SumTask(int[] src, int fromIndex, int toIndex) {
            this.src = src;
            this.fromIndex = fromIndex;
            this.toIndex = toIndex;
        }

        @Override
        protected Integer compute() {
            /*任务的大小是否合适*/
            if (toIndex - fromIndex < THRESHOLD){
//                System.out.println(" from index = "+fromIndex
//                        +" toIndex="+toIndex);
                int count = 0;
                for(int i= fromIndex;i<=toIndex;i++){
                    SleepTools.ms(1);
                     count = count + src[i];
                }
                return count;
            }else{
                //fromIndex....mid.....toIndex
                int mid = (fromIndex+toIndex)/2;
                SumTask left = new SumTask(src,fromIndex,mid);
                SumTask right = new SumTask(src,mid+1,toIndex);
                invokeAll(left,right);
                return left.join()+right.join();
            }
        }
    }


    public static void main(String[] args) {

        int[] src = MakeArray.makeArray();
        /*new出池的实例*/
        ForkJoinPool pool = new ForkJoinPool();
        /*new出Task的实例*/
        SumTask innerFind = new SumTask(src,0,src.length-1);

        long start = System.currentTimeMillis();

        pool.invoke(innerFind);
        //System.out.println("Task is Running.....");

        System.out.println("The count is "+innerFind.join()
                +" spend time:"+(System.currentTimeMillis()-start)+"ms");

    }
}

3、总结

通过测试发现,使用了ForkJoin之后,计算总和的时间要比单线程累加计算所用的时间要长,也就是说并不是所有的任务使用多线程都会变快,因为咱们例子的任务就是简单的累加,如果你的任务比较耗时,或者你的工作量比较大,ForkJoin的优势才会显现出来!我们通过图示和代码讲解了ForkJoin如何使用,怎么使用,如果对XDM有用的话,来个三连!

本文作者:被遗忘的凉白开
本文链接:http://amszlk.com/2021/06/24/qun-jing-ping-yi-zhou-guan-er-fen-er-zhi-zhi-xian-cheng-gong-ju-lei-fork-join-de-shi-yong/
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可