Java8中 Parallel Streams 的陷阱 [译]

转载自https://www.cnblogs.com/imyijie/p/4478074.html

 

Java8 提供了三个我们渴望的重要的功能:Lambdas 、 Stream API、以及接口的默认方法。不过我们很容易滥用它们甚至破坏自己的代码。

今天我们来看看Stream api,尤其是 parallel streams。这篇文章概述了其中的陷阱。

但是首先让我们看看Stream api备受称赞的原因——并行执行。它通过默认的ForkJoinPool,可能提高你的多线程任务的速度。

Parallel Streams 的陷阱

以下是一个使用 parallel streams 完美特性的经典例子。在这个例子中,我们想同时查询多个搜索引擎并且获得第一个返回的结果。

复制代码
 1 public static String query(String question) {2     List<String> engines = new ArrayList<String>() {{3         add("http://www.google.com/?q=");4         add("http://duckduckgo.com/?q=");5         add("http://www.bing.com/search?q=");6     }};7     // get element as soon as it is available8     Optional<String> result = engines.stream().parallel().map((base) -> {9     String url = base + question;
10     // open connection and fetch the result
11     return WS.url(url).get();
12     }).findAny();
13     return result.get();
14 }
复制代码

 

是不是很棒?但是让我们细思深挖一下背后发生了什么。Parallel streams 被父线程执行并且使用JVM默认的 fork join pool: ForkJoinPool.common().(关于fork join 上面有链接)

然而,这里需要注意的一个重要方面是——查询搜索引擎是一个阻塞操作。所以在某时刻所有线程都会调用get()方法并且在那里等待结果返回。

等等,这是我们一开始想要的吗?我们是在同一时间等待所有的结果,而不是遍历这个列表按顺序等待每个回答。

然而,由于ForkJoinPool workders的存在,这样平行的等待相对于使用主线程的等待会产生的一种副作用。现在ForkJoin pool 的实现是:它并不会因为产生了新的workers而抵消掉阻塞的workers。那么在某个时间所有ForkJoinPool.common()的线程都会被用光。

也就是说,下一次你调用这个查询方法,就可能会在一个时间与其他的parallel stream同时运行,而导致第二个任务的性能大大受损。

不过也不要急着去吐槽ForkJoinPool的实现。在不同的情况下你可以给它一个ManagedBlocker实例并且确保它知道在一个阻塞调用中应该什么时候去移除掉卡住的workers。

现在有意思的一点是,在一个parallel stream处理中并不一定是阻塞调用会拖延程序的性能。任何被用于映射在一个集合上的长时间运行的函数都会产生同样的问题。

看下面这个例子

复制代码
1 long a = IntStream.range(0, 100).mapToLong(x -> {
2     for (int i = 0; i < 100_000_000; i++) {
3     System.out.println("X:" + i);
4   }
5   return x;
6 }).sum();
复制代码

 

这段代码同上面那个网络访问的代码遇到了相同的问题。每个lambda的执行并不是瞬间完成的,并且在执行过程中程序中的其他部分将无法访问这些workers。

这意味着任何依赖parallel streams的程序在什么别的东西占用着common ForkJoinPool时将会变得不可预知并且暗藏危机。

那又怎么样?我不还是我程序的主人

确实,如果你正在写一个其他地方都是单线程的程序并且准确地知道什么时候你应该要使用parallel streams,这样的话你可能会觉得这个问题有一点肤浅。然而,我们很多人是在处理web应用、各种不同的框架以及重量级应用服务。

一个服务器是怎样被设计成一个可以支持多种独立应用的主机的?谁知道呢,给你一个可以并行的却不能控制输入的parallel stream?(offer you a predictable parallel stream performance if it doesn’t control the inputs)

一种方式是限制ForkJoinPool提供的并行数。可以通过使用-Djava.util.concurrent.ForkJoinPool.common.parallelism=1 来限制线程池的大小为1。不再从并行化中得到好处可以杜绝错误的使用它。

另一种方式就是,一个被称为工作区的可以让ForkJoinPool平行放置的 parallelStream() 实现。不幸的是现在的JDK还没有实现。

总结

Parallel streams 是无法预测的,而且想要正确地使用它有些棘手。几乎任何parallel streams的使用都会影响程序中无关部分的性能,而且是一种无法预测的方式。我毫不怀疑有人能够设法去正确有效地使用它们。但是在打出stream.parallel()在我的代码里之前我仍然会仔细思考并且再三地审阅包含它的所有代码。

转载于:https://www.cnblogs.com/heroinss/p/10019438.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/364828.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ObjectStreamClass:监视Java对象的序列化

ObjectStreamClass可以是有用的类&#xff0c;用于分析JVM中加载的序列化类的序列化特征。 这篇文章介绍了此类提供的有关已加载序列化类的一些信息。 ObjectStreamClass提供了两个用于查找类的静态方法&#xff1a; lookup&#xff08;class&#xff09;和lookupAny&#xff…

00005在java结果输出_Java-005-运算符详解

计算机的最基本用途之一就是执行数学运算,作为一门计算机语言Java也提供了套丰富的运算符来操纵变量, 可以把运算符分成以下几组算术运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、其他运算符。①算术运算符用在数学表达式中它们的作用和在数学中的作用一样 表格中的…

鼠标拖动改变DIV等网页元素的大小的最佳实践

1.初次实现 1.1 html代码 <html xmlns"http://www.w3.org/1999/xhtml" xml:lang"en" lang"en"><head><meta http-equiv"Content-Type" content"text/html; charsetutf-8" /><title>div change wid…

[WC2006]水管局长

水管局长 题目链接&#xff1a;https://www.luogu.org/problemnew/show/P4172#sub LCT 显然两个点的路径上的边最大要最小在该图最小生成树上 正删倒加&#xff0c;倒着做变成加边操作 加边时判断一下是否能形成更优的生成树&#xff0c;用LCT删除和连接操作即可 1 #include<…

JDBC 4.0鲜为人知的Clob.free()和Blob.free()方法

在会议上谈论jOOQ时&#xff0c;我总是展示此幻灯片&#xff0c;其中包含许多人们经常犯的非常常见的JDBC错误&#xff1a; 此图中的六个常见的JDBC错误 您可以找到错误吗&#xff1f; 其中一些是显而易见的&#xff0c;例如&#xff1a; 第4行&#xff1a;由于第3行的连接…

反沙箱——SetErrorMode

目录 1.前言 2.原理讲解 3.代码实现 4.参考 1.前言 利用SetErrorMode进行反沙箱的技术&#xff0c;在2010年就有被提出&#xff0c;但是之前搜了很久都没有相关内容&#xff0c;这里简单的说一下这个反沙箱的实现。反沙箱参考GandCrab5.2。 2.原理讲解 首先讲一下SetErrorMode这…

使用MyBatis和Spring构建Java Web应用程序

这篇文章将展示如何在Spring环境中使用带有MyBatis框架的MYSQL DB创建学生注册应用程序。 这是一个简单的应用程序&#xff0c;旨在在注册期间从用户收集输入详细信息&#xff0c;将详细信息保存在MYSQL DB中&#xff0c;并在登录期间对它们进行身份验证。 1.使用Maven模板创建…

codeforces 1136E-Nastya Hasn't Written a Legend

传送门&#xff1a;QAQQAQ 题意&#xff1a;有一个数组a和一个数组k&#xff0c;数组a一直保持一个性质&#xff1a;a[i 1] > a[i] k[i]。有两种操作&#xff1a;1&#xff0c;给某个元素加上x&#xff0c;但是加上之后要保持数组a的性质。比如a[i]加上x之后&#xff0c;a…

将Spring MVC RESTful Web服务迁移到Spring 4

1引言 Spring 4为MVC应用程序带来了一些改进 。 在这篇文章中&#xff0c;我将重点介绍宁静的Web服务&#xff0c;并通过采用Spring 3.2实现的项目并将其升级到Spring 4来尝试这些改进。以下几点总结了本文的内容&#xff1a; 从Spring 3.2迁移到Spring 4.0 变化中的Response…

java scrollpane 设置透明_java swing 之 JScrollPane(滚动面板)的使用

/*** java swing 之JScrollPane面板* 在设置界面时&#xff0c;可能会遇到在一个较小的容器窗体中显示一个较大部分的内容&#xff0c;这时可以使用* JScrollPane面板&#xff0c;JscrollPane面板是带滚动条的面板&#xff0c;也是一种容器&#xff0c;但是常用于布置单个* 控件…

软件工程(2019)第三次个人作业

目录 软件工程第三次作业问题描述分析并设计程序程序流程图选择覆盖标准并设计测试样例软件工程第三次作业 项目地址 问题描述 题目(1)&#xff1a;最大连续子数组和&#xff08;最大子段和&#xff09; 背景 问题&#xff1a; 给定n个整数&#xff08;可能为负数&#xff09;组…

Flutter - 创建侧滑菜单

侧滑菜单在安卓App里面非常常见&#xff0c;比如Gmail&#xff0c;Google Play&#xff0c;Twitter等。看下图 网上也有很多创建侧滑菜单的教程&#xff0c;我也来记录一下&#xff0c;自己学习创建Drawer的过程。 1. 创建一个空的App import package:flutter/material.dart;cl…

java框架白话_Java NIO框架Netty教程(二) 白话概念

"Hello World"的代码固然简单&#xff0c;不过其中的几个重要概念(类)和 Netty的工作原理还是需要简单明确一下&#xff0c;至少知道其是负责什。方便自己以后更灵活的使用和扩展。声明&#xff0c;笔者一介码农&#xff0c;不会那么多专业的词汇和缩写&#xff0c;只…

luogu4770 [NOI2018]你的名字 后缀自动机 + 线段树合并

其实很水的一道题吧.... 题意是&#xff1a;每次给定一个串\(T\)以及\(l, r\)&#xff0c;询问有多少个字符串\(s\)满足&#xff0c;\(s\)是\(T\)的子串&#xff0c;但不是\(S[l .. r]\)的子串 统计\(T\)本质不同的串&#xff0c;建个后缀自动机 然后自然的可以想到&#xff0c…

团队计划会议

跟航哥想了挺多要做什么&#xff0c;要完成什么&#xff0c;以什么为主要功能 提出了几个想法&#xff0c;并做了投票 最后决定一起做一个跑腿软件 最初的任务量&#xff1a; 跟航哥商量两个人一人负责两个模块 航哥负责管理员和下单 我负责接单跟其他琐碎的小功能 呐&#xff…

vue.js java php_准吗?Java程序员喜欢AngularJS,PHP程序员喜欢Vue.js!

编程语言与框架或者库之间有联系是很正常的事情&#xff0c;如果我们告诉你&#xff0c;使用某一种编程语言或技术的开发人员可能更喜欢某个框架&#xff0c;你会作何反应呢&#xff1f;Stack Overflow根据网站内最常访问的标签将开发人员分为多个组&#xff0c;并检查了每组每…

结构化日志:出错时你最想要的好朋友

目录 介绍什么是日志&#xff1f;Grab中日志的状况为什么改变&#xff1f;结构化日志支持不同格式的多写开发中类似生产环境的日志因果顺序但为什么要结构化记日志&#xff1f;原文&#xff1a;Structured Logging: The Best Friend You’ll Want When Things Go Wrong 介绍 在…

在vue项目中添加特殊字体

这里的特殊字体&#xff0c;指的是一般用户电脑未安装到本地的字体&#xff0c;要引入这样的字体&#xff0c;首先需要把字体文件下载下来。 就像上图这样的&#xff0c;ttf格式的&#xff0c;然后在项目里添加它。 然后我们在font.css里用font-face规则引入这个字体文件并命名…

使用Spring WS创建合同优先的Web服务

1引言 本文介绍了如何使用来实现和测试SOAP Web服务 Spring Web Services项目 。 本示例使用JAXB2进行&#xff08;取消&#xff09;编组。 为了开发服务&#xff0c;我将使用合同优先的方法&#xff0c;该方法首先定义服务合同&#xff0c;然后基于该合同实施服务。 本文分为…

转载 Net多线程编程—System.Threading.Tasks.Parallel

.Net多线程编程—System.Threading.Tasks.Parallel System.Threading.Tasks.Parallel类提供了Parallel.Invoke&#xff0c;Parallel.For&#xff0c;Parallel.ForEach这三个静态方法。 1 Parallel.Invoke 尽可能并行执行所提供的每个操作&#xff0c;除非用户取消了操作。 方法…