当数据量大的时候,采用并行的方式有时候也不是最好的选择,查看并行流的源码:
default Stream<E> parallelStream() { return StreamSupport.stream(spliterator(), true); } default Spliterator<E> spliterator() { return Spliterators.spliterator(this, 0); }
可以看出parallelStream是将Collection通过Spliterators先切分成小的数据块,至于能比stream快的效果应该是,切分完成后充分利用机器的处理器核来并行执行这些小的数据块,再将结果进行汇聚。而普通的stream应该是属于在一个处理器核上进行并发的处理数据。(有不对的地方还望各位指出,学习学习)
而数据量很大,且需要远程http或其他通信获取数据时,可能就会因为网络、机器等什么其他一些问题而使数据一直处于加载中,或由于超时直接请求断线了,此时考虑异步的执行方式是最好的。
同步API和异步API的对比:
1)同步API就是指当你调用了某个方法(getName()),而调用方(User)在被调用方(getName())运行的过程中会一直等待状态,待被调用方(getName())运行结束完成后,调用方(User)才可以继续运行下一步,这就形成了一种阻塞式调用。
2)异步API就是在指在被调用方(getName())完成计算之前,可能会将它的剩余计算任务交给另外一个线程来执行,此时的线程和调用方就形成了一种异步的操作,也就是非阻塞式调用。
而对于异步执行可以使用工厂方法supplyAsync来创建CompletableFuture:
CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> yourMethod()); 源码: /** * Returns a new CompletableFuture that is asynchronously completed * by a task running in the given executor with the value obtained * by calling the given Supplier. * * @param supplier a function returning the value to be used * to complete the returned CompletableFuture * @param executor the executor to use for asynchronous execution * @param <U> the function's return type * @return the new CompletableFuture */ public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) { return asyncSupplyStage(screenExecutor(executor), supplier); } 你会发现我们还可以自定义一个满足自身业务需求的执行器构造传入。
对于自定义执行器的应用场景举个例子:
假设:你的机器为8核,顺序执行时每1ms处理一个数据
1)当需要处理的集合中的数据量也正好为8,此时使用顺序(stream)执行时需要8ms,而使用并行(parallelStream)或异步(CompletableFuture)执行时因为充分利用处理器所以可能只需要消耗1ms。
2)当需要处理的集合中的数据量也正好为9,此时使用顺序(stream)执行时需要9ms,使用并行(parallelStream)执行时可能需要消耗1.12ms,而使用异步(CompletableFuture)执行时也和并行一样差不多的时间。
对于第二种情况:这是因为他们俩内部都使用的是同样的通用线程池,默认都使用固定数量的线程,也就是默认线程数(Runtime.getRuntime().availableProcessors()的返回值)都一样造成的所消耗的时间相差不大。此时就可以通过自定义执行器来控制线程池的大小,提高并发数,进而来更好的利用系统资源。
对于线程池的相关知识,可以阅读Brian Goetz《Java并发编程实战》这本书籍,里面有很多比较好优化方法。在执行时,要是线程池中的线程数量太多,会因为竞争稀缺的处理器和内存资源,反而浪费大量的时间在上下文切换上。而要是线程数量太少,优惠因为处理器的一些核不能被充分利用,造成资源上的浪费。所以你会看到这本书里面总结了一个公式:
N(threads) = N(cpu) * U(cpu) * (1 + W/C) N(threads): 适合的线程数。 N(cpu): 指处理器的核数目,Runtime.getRuntime().availableProcessors(),也是默认线程数。 U(cpu): 指你所期望的CPU利用率(介于0-1之间)。 W/C: 指等待时间与计算时间的比率。
其他资料:java并发编程:线程池的使用
//自定义执行器
ExecutorService executor = Executors.newFixedThreadPool(Math.min(list.size(), 100), new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); return t; } } );
对于并行流和使用异步执行的选择,当不需要涉及到网络请求、IO处理、等待时间可能有点慢的情况下,建议考虑并行流parallelStream来处理。相反,涉及到网络、IO的时候可以考虑CompletableFuture来执行。
有时候也需要自定义迭代器去处理一些操作:
// 读取文件 static class LineIterator extends AbstractIterator<String> { BufferedReader reader; LineIterator(InputStream in) throws UnsupportedEncodingException { reader = new BufferedReader(new InputStreamReader(in, "utf-8")); } @Override protected String computeNext() { try { String line = reader.readLine(); if (line == null) { reader.close(); return endOfData(); } else { return line; } } catch (IOException e) { } return endOfData(); } }
相关推荐
Java 记录随笔 Java 记录随笔是关于 Java 软件架构设计的笔记,涵盖了软件架构的基本原则、当前流行的技术、数据库存储结构、Web 界面用户接口层、业务层架构、持久层技术、XML 结构化信息传输和存储的重要性等多个...
JAVA_HOME="/usr/lib/jvm/java-8-oracle" PATH="$PATH:$JAVA_HOME/bin" ``` 保存并关闭文件,然后使更改生效: ```bash source /etc/environment ``` 接下来,我们需要安装MySQL 5.7。同样地,使用apt来安装: `...
每四位二进制数对应一个十进制数,如二进制的1101代表十进制的13,因为1*8 + 1*4 + 0*2 + 1*1 = 8 + 4 + 0 + 1 = 13。8421码在某些特定的数字处理场景中很有用,如电子表格软件或计算器。 Java中的位运算,如与(&)...
在Java世界,Map对象转换为实体类通常是通过ORM框架如MyBatis Plus完成的,而实体类转化为JSON则可以借助Jackson或Gson库。例如,使用Gson库,可以写成`Gson gson = new Gson(); String jsonString = gson.toJson...
9. **帮助文档**:附带的开发随笔手册可能包含关于如何使用该记事本的详细说明,对于初学者来说非常有帮助。 开发这样的程序需要对Java语言、SWT库以及面向对象设计有深入理解。通过这个项目,开发者不仅可以掌握...
标题“2014210-2014307笔记随笔”暗示了这是一份时间跨度从2014年2月10日至3月7日的个人学习记录,可能包含了作者在IT领域的所学所悟,特别是关于编程、软件开发或系统设计的思考。由于描述部分为空,我们无法直接...
在开发“Android App_云随笔课程设计”项目时,我们面临的是构建一个移动应用程序,旨在帮助用户便捷地记录他们的日常生活、旅行体验、心情点滴以及学习笔记等。这个应用程序的关键特性在于其同步功能,它将用户的...
JavaThings-Java安全漫谈笔记相关《 Java安全漫谈》是我在写的一点Java学习相关的随笔,不是很严谨,也不是啥高科技。这个存储库主要是记录并整理一下,附加一些代码。Java安全漫谈目录 人口统计字节码:远程字节码...
Ibatis 是一款轻量级的Java持久层框架,它的核心思想是将SQL语句与Java代码分离,使得开发者可以更加灵活地控制SQL的编写,同时避免了传统的JDBC中的大量模板代码,提高了开发效率和代码的可维护性。在本文中,我们...
例如,可能会讲解使用如Python、C++或Java等语言进行系统开发,或者如何利用现有的开源项目如OPC-UA、Modbus等进行通信协议的实现。源码分析部分可能涉及代码调试、性能优化和错误处理等内容。 “工具”标签表明...
Apache Log4j2 是一个广泛使用的Java日志记录库,它提供了一个强大和灵活的方式来记录应用程序事件。Log4j2手册详细介绍了该库的各个方面,包括架构、迁移、API、配置、Web应用程序集成、插件、查找、Appenders、...
基于JAVA幼儿园家园共育平台设计与实现 开发语言 JavaWeb前端语言 开发工具:六年特雷利JIDEA ...童言稚语:每月记录一次幼儿有趣的话语,文字展示。 育儿头条:育儿新闻文章。管理员上传,可评论点赞
java 源码 博客 一杯82年的JAVA 大家好,我是练习时常两年半的JAVA练习生,爱好是 ...博客专用仓库,主要记录一些学习和实践的总结,感兴趣的朋友可以点个watch或star。 随笔 探索JAVA并发 从0.5到1写个RPC框架
无论是通过阅读"课堂问题随笔.txt"来解决疑惑,还是通过"必须记住的代码君们"来熟悉常用代码,亦或是通过"Entertainment"中的项目来提升编程技巧,都能有效地促进Java学习的进程。同时,"总结文件"和"瞎搞"部分则...
1. **技术基础知识**:随笔可能涵盖基础的编程语言知识,如Python、Java或C++的语法特性,数据结构和算法的应用,以及软件工程的基本原则。 2. **项目经验分享**:作者可能会分享他们在实际项目中遇到的问题及解决...
列表参考国光大佬的国光的安全随笔记录 安全技能 该技能表不用按顺序进行学习,但是比较高级的我会放最后面,因为我也不会,需要花时间慢慢加。 总结我这几年的一点经验:安全需要学习的技术太多了,特别是红队、...
Java自动内存管理机制包含两部分:内存分配和内存回收,要想理解内存分配和回收的机制,则需要了解下Java内存区域(Java运行时数据区),这篇随笔将按照下面的线索进行逐步解析:1.Java运行时数据区2.对象“已死”的...
3. 在代码中使用:在Java代码中,通过Logger类获取日志实例,然后调用如info(), warn(), error()等方法记录日志。 四、日志子文件Logger 压缩包中的"Logger"可能是具体的日志实现类或配置文件。如果是类文件,它...
MiaoWu毕业设计-流浪猫收养系统过程随笔记录通知:1.用户关注用户2.关注的用户发帖3.帖子审核结果4.领养申请5.领养审核结果发帖:需发帖人有联系方式帖子详情页 数据获取顺序调整实现头像修改功能修改记录1.修改猫咪...