前言

看到题目是不是有点疑问:你确定你没搞错?!数组求和???遍历一遍累加起来不就可以了吗???

是的,你说的都对,都听你的,但是我说的就是数组求和,并且我也确实是刚刚学会。╮(╯▽╰)╭

继续看下去吧,或许你的疑问会解开↓

注:记录于学习完《Java 8 实战》数据并行处理与性能,如果有错误,欢迎大佬指正

传统方式

求和方法

我相信你和我一样,提到数组求和,肯定最想想到的就是将数组迭代一遍,累加迭代元素。这是最简单的一种方式,代码实现如下:

public static long traditionSum(long[] arr){

//和

long sum = 0;

//遍历数组中的每个元素

for (long l : arr) {

//累加

sum += l;

}

return sum;

}

性能测试方法

为了便于我们测试性能,我们写一个比较通用的测试函数,用来记录对每种方式的运行时间,直接看代码吧!

public static long test(Function function, long[] arr){

//记录最快的时间

long fasttime = Long.MAX_VALUE;

//对函数调用10次

for (int i = 0; i < 10; i++) {

//记录开始的系统时间

long start = System.nanoTime();

//执行函数

long result = function.apply(arr);

//获取运行时间转换为ms

long time = (System.nanoTime() - start) / 1_000_000;

//打印本次的就和结果

System.out.println("结果为:" + result);

//更新最快的时间

if (time < fasttime) {

fasttime = time;

}

}

return fasttime;

}

性能测试代码解释

传入参数Function function: 我们需要测试的函数,稍后我们会把每种求和方式都传入到这个参数里面。如果你对java 8的新特性(Lambda表达式、行为参数化、方法引用等)不熟悉,那么你可以理解为Function是一个匿名类,我们传入的求和方法会放到function.apply()的方法中,我们调用apply()方法,实际上就是调用我们传入的求和方法。

Function的泛型: 第一个为我们求和方法需要传入的参数的类型(传入一个long类型的数组作为待求和数组),第二个为我们的求和方法返回值的类型(返回数组的和为long)

long[] arr:待求和数组

关于为什么会调用10次:任何的Java代码都需要多执行几次才会被JIT编译器优化,多执行几次是为了保证我们测量性能的准确性。

数据准备

方法有了,我们当然要准备好我们的测试数据了,为了简便起见,我们直接顺序生成1到100,000,000(1亿)来最为待求和的数组:

long[] longs = LongStream.rangeClosed(1, 100_000_000).toArray();

测试性能

数据有了,我们可以测试一下传统方式的性能了(所在类TestArraysSum)

public static void main(String[] args) {

long[] longs = LongStream.rangeClosed(1, 100_000_000).toArray();

//执行测试函数

long time = test(TestArraysSum::traditionSum, longs);

System.out.println("时间为: " + time + "ms");

}

结果:

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

时间为: 62ms

继续看其他方式

Stream流的顺序执行方式

求和方法

java 8的流可谓是非常的强大,配合lambda表达式和方法引用,极大的简化了对数据处理方面,下面是使用流对数组进行顺序求和

public static long sequentialSum(long[] arr){

return Arrays.stream(arr)

.reduce(0L, Long::sum);

}

代码解释

Arrays.stream(arr)将我们传入的数组变为一个流(此处没有Java包装类与原始类型的装箱和拆箱,装箱和拆箱会极大影响性能,应该尽量避免)

.reduce(0L, Long::sum):0L是初始值,Long::sum通过方法引用的方式使用Long提供的求和函数,对数组的每一个元素都进行求和

性能测试

Java 8让我们的代码极大的简化了,那么性能如何呢?

我们将main方法内执行求和方法部分换为调用这个方法看看

long time = test(TestArraysSum::sequentialSum, longs);

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

时间为: 62ms

emmmm 好像差不多,Ծ‸Ծ,先不急,Java 8的流给我们带来的另一大好处还没用上呢,下面我们就来看看吧

Stream流的并行执行

求和方法

Java 8 的Stream流可以让我们非常简单的去使用多线程解决问题,而我们的求和需求好像完美适合多线程问题去解决

public static long parallelSum(long[] arr){

return Arrays.stream(arr)

.parallel()

.reduce(0L, Long::sum);

}

代码解释

.parallel():与顺序流实现相比,仅仅是多调用了一个parallel()方法,他的作用就是将顺序流转化为并行流(其实就是改变了一下boolean标志),如何并行执行呢,不用我们实现,无脑调用就好了

性能测试

long time = test(TestArraysSum::parallelSum, longs);

结果

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

时间为: 52ms

哦吼~这就很舒服了,是不是瞬间就快了

注:并行流内部默认使用ForkJoinPool的线程池,线程数量默认为计算机处理器的数量,使用Runtime.getRuntime().availableProcessors()可以获取处理器核心数

(我的测试环境是8个),可是设置这个值,但是只能全局设置,所以最好还是不要更改

是不是疑问我们除了调用parallel()方法以外什么都没干,究竟是怎么实现多线程的呢,其实并行流底层使用的是Java 7的分支/合并框架,下面我们就看一下使用分支/合并框架实现多线程求和吧!

分支合并框架的实现方式

分支合并框架的目的是以递归的方式将可以并行的任务拆分成更小的子任务,然后将每个子任务的结果进行合并生成整体结果。

求和方法

我们可以继承RecursiveTask实现其compute()方法

分支合并实现的类ForkJoinSumCalculator

package java_8.sum;

import java.util.concurrent.RecursiveTask;

public class ForkJoinSumCalculator extends RecursiveTask {

//任务处理的数组

private final long[] arr;

//当前任务处理的开始和结束索引

private final int start;

private final int end;

//划分到处理数组的长度10_000_000变不来划分,进而合并

public static final long THRESHOLD = 10_000_000;

//公共的构造函数,用来创建主任务

public ForkJoinSumCalculator(long[] arr){

this(arr,0,arr.length);

}

//私有的构造函数,用来创建子任务

private ForkJoinSumCalculator(long[] arr, int start, int end){

this.arr = arr;

this.start = start;

this.end = end;

}

//实现的方法

@Override

protected Long compute() {

//当时子任务处理长度

int length = end - start;

//当数组处理长度足够小时

if (length <= THRESHOLD){

//进行合并

return computeSequentially();

}

//创建第1个子任务对前面一半数组进行求和

ForkJoinSumCalculator leftTask = new ForkJoinSumCalculator(arr, start, start + length / 2);

//使用线程池中的另一个线程求和前一半

leftTask.fork();

//创建第2个子任务对后一半数组进行求和

ForkJoinSumCalculator rightTask = new ForkJoinSumCalculator(arr, start + length / 2, end);

//直接使用当前线程进行求和 获取求和结果

Long rightResult = rightTask.compute();

//获取前一半的求和结果

Long leftTesult = leftTask.join();

//合并

return leftTesult + rightResult;

}

//合并是的调用方法 迭代求和

private long computeSequentially(){

long sum = 0;

for (int i = start; i < end; i++) {

sum += arr[i];

}

return sum;

}

}

public static final long THRESHOLD = 10_000_000;

划分的界线使我随便设定的当前值的情况下会划分为10个线程

然后我们就可以编写我们的求和方法了

public static long forkJoinSum(long[] arr){

ForkJoinSumCalculator calculator = new ForkJoinSumCalculator(arr);

return new ForkJoinPool().invoke(calculator);

}

性能测试

long time = test(TestArraysSum::forkJoinSum, longs);

结果:

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

结果为:5000000050000000

时间为: 53ms

还不错,跟并行流的性能差不多

由于分支合并时的递归调用也消耗性能,因此我们更改public static final long THRESHOLD = 10_000_000;的大小时,运行时间会差距很大。

具体更改多少效率最高,这个真的不好说

总结

使用了4种方式完成数组求和

使用传统方式(遍历)效率其实也不低,因为实现方式比较接近底层

使用流极大简化了数组处理

并行流在适合的场景下可以大展身手

并行流使用分支合并框架实现

Java之数组篇

动手动脑,第六次Tutorial--数组 这次的Tutorial讲解了Java中如何进行数组操作,包括数组声明创建使用和赋值运算,写这篇文章的目的就是通过实际运用已达到对数组使用的更加熟练,下面是实践 ...

java中数组的相关知识

1. 2.数组的命名方法 1)int[]ages=new int[5]; 2) int[]ages; ages=new int[5]; 3)int[]ags={1,2,3,4,5}; 4)int[ ...

Java基础——数组应用之StringBuilder类和StringBuffer类

接上文:Java基础——数组应用之字符串String类 一.StringBuffer类 StringBuffer类和String一样,也用来代表字符串,只是由于StringBuffer的内部实现方式和 ...

java将数组中的零放到末尾

package com.shb.java; /** * 将数组中的0放到数组的后边,然后原来的非零数的顺序不改变 * @author BIN * */ public class Demo2{ publ ...

Java中数组的特性

转载:http://blog.csdn.net/zhangjg_blog/article/details/16116613 数组是基本上所有语言都会有的一种数据类型,它表示一组相同类型的数据的集合,具 ...

在java 中&comma;数组与 List&lt&semi;T&gt&semi; 类型的相互转换

在java中,数组与List 之前进行互相转换,转换方法可总结为以下几种: 一. 将 数组转换成List 1. 使用 Collections 的addAll 方法 ...

Java RGB数组图像合成 ImageCombining &lpar;整理&rpar;

/** * Java RGB数组图像合成 ImageCombinning (整理) * * 2016-1-2 深圳 南山平山村 曾剑锋 * * 注意事项: * 1.本程序为java程序,同时感谢您花费 ...

java对象数组

问题描述:     java 对象数组的使用 问题解决: 数组元素可以是任何类型(只要所有元素具有相同的类型) 数组元素可以是基本数据类型 数组元素也可以是类对象,称这样的数组为对象数组.在这种情况下 ...

随机推荐

WPF-编程问题和解决

1.wpf中点击button按钮后怎么让TextBlock显示button按钮的值?

Javascript 与正则表达式

一.正则表达式(regular expression简称res) 二.元字符及其在正则表达式上下文中的行为 三.正则表达式的常用方法 四.与正则表达式有关的字符串对象的方法 五.常用的正则表达式的操作 ...

Fence Repair(poj 3253)

题意: 有一个农夫要把一个木板钜成几块给定长度的小木板,每次锯都要收取一定费用,这个费用就是当前锯的这个木版的长度 给定各个要求的小木板的长度,及小木板的个数n,求最小费用 提示: 以 3 5 8 5 ...

Android studio导入Eclipse项目,和一些错误的解决

Android studio导入Eclipse开发的项目步骤如下 如果已经打开Android studio的话就选择你已打开的项目,关闭然后导入 开始导入 导入完成. 2.项目出错 Error:(13 ...

webuploader 实现图片批量上传

1.导入资源 2.JSP代码

&lt ...

java-数组排序--插入排序

插入排序 想象着你的左手拿着一手好牌[1,1,1,2,6,6,6,9,9],此时你从桌面上又抽出一张牌[1],你将抽出的牌,从又往左,依次与左手的牌进行比较(只以数字进行对比),当抽出的牌第一次不再大 ...

第24章 退出 - Identity Server 4 中文文档&lpar;v1&period;0&period;0&rpar;

注销IdentityServer就像删除身份验证cookie一样简单,但是为了完成联合注销,我们必须考虑将用户从客户端应用程序(甚至可能是上游身份提供者)中签名. 24.1 删除认证 要删除身份验证c ...

snmp 里面oid对应的信息 MIB

系统参数(1.3.6.1.2.1.1) OID 描述 备注 请求方式 .1.3.6.1.2.1.1.1.0 获取系统基本信息 SysDesc GET .1.3.6.1.2.1.1.3.0 监控时间 s ...

python数据结构之栈

栈 栈(stack),有些地方称为堆栈,是一种容器,可存入数据元素.访问元素.删除元素,它的特点在于只能允许在容器的一端(称为栈顶端指标,英语:top)进行加入数据(英语:push)和输出数据(英语: ...

使用badblocks命令检测、修复硬盘坏道&lpar;待验证&rpar;

今天我的新硬盘到了.暂时没想好怎么用它.可以把它装入光驱位硬盘架给G430用,也可以把它当成移动硬盘来用. 想起以前记录过一个badblocks的用法,用来检查坏道,这里再贴一遍备用. ####### ...

java 数组怎么求和,感动,我终于学会了Java对数组求和相关推荐

  1. 感动,我终于学会了用Java对数组求和

    前言 看到题目是不是有点疑问:你确定你没搞错?!数组求和???遍历一遍累加起来不就可以了吗??? 是的,你说的都对,都听你的,但是我说的就是数组求和,并且我也确实是刚刚学会.╮(╯▽╰)╭ 继续看下去 ...

  2. 自学java第2天(随机数,猜字游戏,数组)

    一, 生成随机数 代码如下 package day2;import java.util.Random;public class randomdemo1 {public static void main ...

  3. 18、Java面向对象——类和对象的关系及应用、对象数组的应用

    目录 课前先导: 一.什么是类? 二.类的创建 三.什么是对象? 四.对象的创建.赋值:方法的调用 五.定义类和对象的三种方法 六.对象数组 七.来了,你们要的对象 课前先导: 在刚开始学习java的 ...

  4. Java实现有序数组和无序数组_【算法】字典的诞生:有序数组 PK 无序链表

    参考资料 <算法(java)>                           - - Robert Sedgewick, Kevin Wayne <数据结构>       ...

  5. java 数组 题_(第22讲)java数组的一些编程题

    1. 要求输入一组英文字符串数组,让这个字符串数组中前面一个元素的最后一个 字母和下一个元素的首位上的字母相等,并且每个元素的长度大于等于2且小于等于100 public static void ma ...

  6. 终于有人把Java技术知识面试体系整理出来了,这些文档让你的面试稳如泰山

    程序猿,一个懂JAVA语言.C++语言.C语言.PHP语言等非人类语言的人类,在普通人看来,做好程序猿太难了.在IT行业有这样一句话:面试造火箭,工作拧螺丝,就是针对程序员的.可想而知,能进入程序猿行 ...

  7. Java黑皮书课后题第1章:1.6(数列求和)编写程序,显示1+2+3+4+5+6+7+8+9的结果

    Java黑皮书课后题第1章:1.6(数列求和) 题目 题目描述 槽点 代码 代码块 区分println(x)与println("x") 法1法2选用 修改日志 题目 题目描述 1. ...

  8. java怎么把数据封进对象里_(Java)想把数组中一条一条的数据全部放入对象中去..要怎么做呢...

    展开全部 Java把数组中一条一条的数据全部放入对象中去操作如下: 1.先获取到数组中的数据dataArray数据. 2.接32313133353236313431303231363533e58685 ...

  9. 左神算法:未排序正数数组中累加和为给定值的最长子数组长度(Java版)

    本题来自左神<程序员代码面试指南>"未排序正数数组中累加和为给定值的最长子数组长度"题目. 题目 牛客OJ:未排序数组中累加和为给定值的最长子数组长度 题解 本文提供的 ...

最新文章

  1. python 函数返回值的特殊情况
  2. 开源项目JacpFX
  3. CCIE理论-第八篇-SD-WAN(三)+DAI(动态ARP检测)
  4. datatables 配套bootstrap样式使用小结(2) ajax篇
  5. (转)SpringMVC学习(七)——Controller类的方法返回值
  6. 九江职业学院计算机专业怎么样,请问九江职业大学和九江职业技术学院,相比之下哪个好一点?...
  7. MySQL半同步复制 - 优点、缺点、配置
  8. 《计算机网络 第七版》读后感
  9. 主机无法ping通虚拟机xp系统
  10. Android模拟器哪个稳定,哪个安卓模拟器好 什么安卓模拟器稳定流畅速度快不卡顿...
  11. 通达OA任意用户登录漏洞手工复现
  12. journey、voyage、trip、tour、travel的用法区别
  13. android studio 导出 aar,Android Studio 导出 .aar包的操作流程
  14. 安卓demo,新手开发教程之开发备忘录
  15. 传世私服服务器列表不显示,关于传世私服的人物名字显示设置详解
  16. php抓取搜狗图片,搜狗美图 API 接口请求调用
  17. OPEN3D学习笔记(六)——Multiway registration
  18. java里precision,int precision()
  19. linux下编译安装ntfs,内核编译安装 (用NTFS模块)
  20. python 发送邮件给多人

热门文章

  1. 计算机网络的super super easy 教程 | 基础 及 数据链路层
  2. 【支线】基于Aidlux的Arduino小车
  3. 【记录】前端知识点 - Vue
  4. ​​如何搭建自己的魔兽世界服务器
  5. 零基础语法入门第四讲 代词的主格和宾格
  6. 订单接口获取商品订单详情/物流信息/交易订单
  7. 爬取京东图书商品信息
  8. 4G套餐用户挺住了,运营商比你们急,会给优惠的低价流量
  9. 1. SpringBoot 整合 Canal
  10. Python判断大小写和数字和常用方法