当前位置: 移动技术网 > IT编程>开发语言>Java > 如何高效的计算1~1000000000之和

如何高效的计算1~1000000000之和

2020年07月18日  | 移动技术网IT编程  | 我要评论

简单的来算,我们可以采用 for while 之类循环来计算,下面采用的for循环

 static void forSum(){
        long start = System.currentTimeMillis();
        long sum = 0;
        for (long i = 0; i <= 10_0000_0000; i++) {
            sum+=i;
        }
        long end = System.currentTimeMillis();
        System.out.println("for求和="+sum+",所花时间为:"+(end-start));
    }

我们可以想想怎么才能更有效率,for是单个线程也即是主线程在执行计算,如果多个线程同时执行计算呢?速度会不会快些,试试

static void poolSum(){
        long start = System.currentTimeMillis();
        ForkJoinPool forkJoinPool = ForkJoinPool.commonPool();
        ForkJoinTask<Long> submit = forkJoinPool.submit(new SumTask(0L, 10_0000_0000L));
        try {
            long sum = submit.get();
            long end = System.currentTimeMillis();
            System.out.println("ForkJoinPool求和="+sum+",所花时间为:"+(end-start));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
static class SumTask extends RecursiveTask<Long> {
        private static final int THRESHOLD = 50_0000;//阈值
        long start;
        long end;

        public SumTask(long start, long end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Long compute() {
            long sum = 0;
            //当end与start之间的差小于threshold时,开始进行实际的累加
            if (end - start < THRESHOLD) {
                for (long i = start; i <= end; i++) {
                    sum += i;
                }
                return sum;
            } else {//当end与start之间的差大于threshold,即要累加的数超过threshold个的时候,将大任务分解成小任务
                long middle = (start + end) / 2;
                SumTask left = new SumTask(start, middle);
                SumTask right = new SumTask(middle+1, end);
                //并行执行两个小任务
                left.fork();
                right.fork();
                //把两个小任务累加的结果合并起来
                return left.join() + right.join();
            }
        }
    }


既然多个线程可以,那么多个流并行计算,是不是也可以呢?

    static void streamSum(){
        long start = System.currentTimeMillis();
        long sum = LongStream.rangeClosed(0, 10_0000_0000).parallel().reduce(0,Long::sum);
        long end = System.currentTimeMillis();
        System.out.println("streamSum求和="+sum+",所花时间为:"+(end-start));
    }

运行试试,看看执行的效率怎样?
在这里插入图片描述
我们发现好像使用并行流要快一些,其次是多线程,最后是单个线程,那么一定是这样的吗?不急,往下看

我把 THRESHOLD = 50_0000;改动了一下,如下:

static class SumTask extends RecursiveTask<Long> {
 private static final int THRESHOLD = 500;//阈值

在运行试试:
在这里插入图片描述
发现多线程计算时间变长了,其实这个和阈值有关,我们可以这样想,一个线程池的线程数是不是有限的,我们一直递归下去,不断创建线程,当多出了池子里的线程数,执行的时候就会有线程在等待的,而且,这还和 ForkJoinPool 的工作特点(工作窃取)有关。比如一个工作队列在执行任务,还剩最后一个任务,此时其他的线程来抢任务,就会出现短暂的等待状态。

有兴趣的小伙伴可以去了解一下

本文地址:https://blog.csdn.net/qq_42224683/article/details/107405623

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网