返回顶部
首页 > 资讯 > 精选 >ParallelStream使用的坑怎么解决
  • 445
分享到

ParallelStream使用的坑怎么解决

2023-06-17 04:06:36 445人浏览 独家记忆
摘要

今天小编给大家分享一下ParallelStream使用的坑怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。比如下面的代

今天小编给大家分享一下ParallelStream使用的坑怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

比如下面的代码片段,让人阅读的时候就像是读诗一样。但是一旦用不好,也是会要命的。

List<Integer> transactionsIds = widgets.stream()              .filter(b -> b.getColor() == RED)              .sorted((x,y) -> x.getWeight() - y.getWeight())              .mapToInt(Widget::getWeight)              .sum();

这段代码有一个关键的函数,那就是stream。通过它,可以将一个普通的list,转化为流,然后就可以使用类似于管道的方式对list进行操作。总之,用过的都说好。

对这些函数还不是太熟悉?可以参考:《到处是map、flatMap,啥意思?》

问题来了

假如我们把stream换成parallelStream,会发生什么情况?

根据字面上的意思,流会从串行 变成并行。

既然是并行,那用屁股想一想,就知道这里面肯定会有线程安全问题。不过我们这里讨论的并不是要你使用线程安全的集合,这个话题太低级。现阶段,知道在线程不安全的环境中使用线程安全的集合,已经是一个基本的技能。

这次踩坑的地方,是并行流的性能问题。

我们用代码来说话。

下面的代码,开启了8个线程,这8个线程都在使用并行流进行数据计算。在执行的逻辑中,我们让每个任务都sleep  1秒钟,这样就能够模拟一些I/O请求的耗时等待。

使用stream,程序会在30秒后返回,但我们期望程序能够在1秒多返回,因为它是并行流,得对得起这个称号。

测试发现,我们等了好久,任务才执行完毕。

static void paralleTest() {     List<Integer> numbers = Arrays.asList(             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,             10, 11, 12, 13, 14, 15, 16, 17, 18, 19,             20, 21, 22, 23, 24, 25, 26, 27, 28, 29     );     final long begin = System.currentTimeMillis();     numbers.parallelStream().map(k -> {         try {             Thread.sleep(1000);             System.out.println((System.currentTimeMillis() - begin) + "ms => " + k + " \t" + Thread.currentThread());         } catch (InterruptedException e) {             e.printStackTrace();         }         return k;     }).collect(Collectors.toList()); }  public static void main(String[] args) { //    System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start();     new Thread(() -> paralleTest()).start(); }

实际上,在不同的机器上执行,这段代码花费的时间都不一样。

既然是并行,那肯定得有个并行度。太低了,体现不到并行的能能力;太大了,又浪费了上下文切换的时间。我是很沮丧的发现,很多高级研发,将线程池的各种参数背的滚瓜烂熟,各种调优,竟然敢睁一只眼闭一只眼的在I/O密集型业务中用上parallelStream。

要了解这个并行度,我们需要查看具体的构造方法。在ForkJoinPool类中找到这样的代码。

try {  // ignore exceptions in accessing/parsing properties     String pp = System.getProperty         ("java.util.concurrent.ForkJoinPool.common.parallelism");     if (pp != null)         parallelism = Integer.parseInt(pp);     fac = (ForkJoinWorkerThreadFactory) newInstanceFromSystemProperty(         "java.util.concurrent.ForkJoinPool.common.threadFactory");     handler = (UncaughtExceptionHandler) newInstanceFromSystemProperty(         "java.util.concurrent.ForkJoinPool.common.exceptionHandler"); } catch (Exception ignore) { }  if (fac == null) {     if (System.getSecurityManager() == null)         fac = defaultForkJoinWorkerThreadFactory;     else // use security-managed default         fac = new InnocuousForkJoinWorkerThreadFactory(); } if (parallelism < 0 && // default 1 less than #cores     (parallelism = Runtime.getRuntime().availableProcessors() - 1) <= 0)     parallelism = 1; if (parallelism > MAX_CAP)     parallelism = MAX_CAP;

可以看到,并行度到底是多少,是由下面的参数来控制的。如果无法获取这个参数,则默认使用 CPU个数-1 的并行度。

可以看到,这个函数是为了计算密集型业务去设计的。如果你喂给它一大堆任务,它就会由并行执行退变成类似于串行的效果。

-Djava.util.concurrent.ForkJoinPool.common.parallelism=N

即使你使用-Djava.util.concurrent.ForkJoinPool.common.parallelism=N设置了一个初始值大小,它依然有问题。

因为,parallelism这个变量是final的,一旦设定,不允许修改。也就是说,上面的参数只会生效一次。

张三可能使用下面的代码,设置了并行度大小为20。

System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "20");

李四可能用同样的方式,设置了这个值为30。那实际在项目中用的是哪个值,那就得问JVM是怎么加载的类信息了。

这种方式并不太非常靠谱。

一种解决方式

我们可以通过提供外置的forkjoinpool,也就是改变提交方式,来实现不同类型的任务分离。

代码如下所示,通过显式的代码提交,即可实现任务分离。

ForkJoinPool pool = new ForkJoinPool(30);  final long begin = System.currentTimeMillis(); try {     pool.submit(() ->             numbers.parallelStream().map(k -> {                 try {                     Thread.sleep(1000);                     System.out.println((System.currentTimeMillis() - begin) + "ms => " + k + " \t" + Thread.currentThread());                 } catch (InterruptedException e) {                     e.printStackTrace();                 }                 return k;             }).collect(Collectors.toList())).get(); } catch (InterruptedException e) {     e.printStackTrace(); } catch (ExecutionException e) {     e.printStackTrace(); }

这样,不同的场景,就可以拥有不同的并行度。这种方式和CountDownLatch有异曲同工之妙,我们需要手动管理资源。

以上就是“ParallelStream使用的坑怎么解决”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: ParallelStream使用的坑怎么解决

本文链接: https://lsjlt.com/news/287070.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • ParallelStream使用的坑怎么解决
    今天小编给大家分享一下ParallelStream使用的坑怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。比如下面的代...
    99+
    2023-06-17
  • 使用aot的坑怎么解决
    本篇内容主要讲解“使用aot的坑怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“使用aot的坑怎么解决”吧!启动参数固定化jaotc可以通过加-J参数来指定jvm的启动参数。我们尝试使用c...
    99+
    2023-06-03
  • Mybatis Plus使用@TableId坑怎么解决
    这篇文章主要讲解了“Mybatis Plus使用@TableId坑怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Mybatis Plus使用@TableId坑怎么...
    99+
    2023-06-21
  • golang recover函数使用的坑怎么解决
    这篇文章主要讲解了“golang recover函数使用的坑怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“golang recover函数使用的坑怎么解决”吧!一...
    99+
    2023-07-05
  • vue使用Swiper踩坑解决避坑
    目录我的Swiper定义:报错信息:保留默认名class:swiper-container查看GitHub我的Swiper定义: Failed to execute 'get...
    99+
    2023-05-20
    vue Swiper踩坑解决 vue Swiper避坑
  • mybatisplus的坑怎么解决
    这篇文章主要讲解了“mybatisplus的坑怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“mybatisplus的坑怎么解决”吧!mybatisplus的坑 insert标签ins...
    99+
    2023-06-21
  • 怎么使用shardingsphere对SQLServer坑进行解决
    这篇“怎么使用shardingsphere对SQLServer坑进行解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么使...
    99+
    2023-06-29
  • 使用vue导出excel遇到的坑怎么解决
    这篇“使用vue导出excel遇到的坑怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“使用vue导出excel遇到的坑...
    99+
    2023-06-29
  • springboot中用undertow的坑怎么解决
    这篇“springboot中用undertow的坑怎么解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“springboot...
    99+
    2023-06-29
  • 使用shardingsphere对SQLServer坑的解决
    背景:最近一个使用SQLServer的项目,业务量太大,开始对业务有影响了,因此用户要求升级改造,技术上采用shardingsphere进行分库分表。 经过一系列调研,设计。。。哐哐...
    99+
    2024-04-02
  • 解决JDK8的ParallelStream遍历无序的问题
    JDK8的ParallelStream遍历无序 ParallelStream其实就是一个并行执行的流 它通过默认的ForkJoinPool,可能提高你的多线程任务的速度. Strea...
    99+
    2024-04-02
  • 怎么解决Static坑
    这篇文章主要介绍“怎么解决Static坑”,在日常操作中,相信很多人在怎么解决Static坑问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么解决Static坑”的疑惑有所帮...
    99+
    2024-04-02
  • python的ImageTk.PhotoImage坑怎么解决
    这篇文章主要介绍“python的ImageTk.PhotoImage坑怎么解决”,在日常操作中,相信很多人在python的ImageTk.PhotoImage坑怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家...
    99+
    2023-07-04
  • Golang的strings.Split()坑怎么解决
    这篇文章主要介绍“Golang的strings.Split()坑怎么解决”,在日常操作中,相信很多人在Golang的strings.Split()坑怎么解决问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Gol...
    99+
    2023-06-30
  • mybatis的test坑怎么解决
    今天小编给大家分享一下mybatis的test坑怎么解决的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。概述mybatis使用...
    99+
    2023-07-05
  • C语言中sizeof函数使用的坑怎么解决
    这篇文章主要介绍“C语言中sizeof函数使用的坑怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C语言中sizeof函数使用的坑怎么解决”文章能帮助大家解决问题。先来看这样一段代码int&n...
    99+
    2023-06-29
  • 解决spring-boot使用logback的大坑
    最近在写一个logback的kafka appender,无意中发现spring-boot在使用logback时的一个坑 用ConsoleAppender.java来举例,假设在lo...
    99+
    2024-04-02
  • 解决使用openpyxl时遇到的坑
    最近在用python处理Excel表格是遇到了一些问题 1, xlwt最多只能写入65536行数据, 所以在处理大批量数据的时候没法使用 2, openpyxl 这个库, 在使用的时...
    99+
    2024-04-02
  • 使用@JsonFormat的一个坑及解决
    目录使用@JsonFormat的一个坑及解决解决如下JsonFormat的时间格式踩坑使用@JsonFormat的一个坑及解决 spring boot项目 ,mysql数据库的dat...
    99+
    2024-04-02
  • 使用fileReader的一个坑及解决
    目录关于fileReader的一个坑fileReader在ios上面的坑(图片转base64)关于fileReader的一个坑 在用fileReader做图片浏览时, 使用base6...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作