并行化流被分成多个块,每个块独立处理,结果在最后汇总。

CPU密集型代码如下:

private long countPrimes(int max) {
    return range(1, max).parallel().filter(this::isPrime).count();
}
private boolean isPrime(long n) {
    return n > 1 && rangeClosed(2, (long) sqrt(n)).noneMatch(divisor -> n % divisor == 0);
}

countPrimes 计算1到最大值之间的素数的数量。数字流由range方法创建,切换到并行模式,过滤掉非素数,剩余的计算总数。由于isPrime 方法极其无效且占用大量CPU,我们可以利用并行化并利用所有可用的CPU内核。

我们来看另一个例子:

private List<StockInfo> getStockInfo(Stream<String> symbols) {
     return symbols.parallel()
            .map(this::getStockInfo) //slow network operation
            .collect(toList());
}

输入是一个股票代码列表,我们必须调用慢速网络操作来获取有关股票的一些细节。在这里,我们不处理CPU密集型操作,但我们也可以利用并行化。并行执行多个网络请求是个好主意。同样,并行流的一个很好的任务,你同意吗?

如果您这样做,请再次查看上一个示例。有一个很大的错误。你看到了吗?问题是所有并行流都使用公共fork-join线程池。如果提交长时间运行的任务,则会有效地阻塞池中的所有线程。因此,您将阻塞使用并行流的所有其他任务。

想象一下servlet环境,当一个请求调用时getStockInfo() ,另一个请求调用  countPrimes()。即使每个都需要不同的资源,也会阻止另一个。更糟糕的是,你不能为并行流指定线程池; 整个类加载器必须使用相同的。

让我们在下面的例子中说明它:

private void run() throws InterruptedException {
 ExecutorService es = Executors.newCachedThreadPool();
 // Simulating multiple threads in the system
 // if one of them is executing a long-running task.
 // Some of the other threads/tasks are waiting
 // for it to finish
 es.execute(() -> countPrimes(MAX, 1000));
 //incorrect task
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.execute(() -> countPrimes(MAX, 0));
 es.shutdown();
 es.awaitTermination(60, TimeUnit.SECONDS);
}
private void countPrimes(int max, int delay) {
  System.out.println( range(1, max).parallel() .filter(this::isPrime).peek(i -> sleep(delay)).count() ); }

在这里,我们模拟系统中的六个线程。所有这些都在执行CPU密集型任务,第一个被“暂停”,在它找到素数后就睡了一秒钟。这只是一个人为的例子; 你可以想象一个被卡住或执行阻塞操作的线程。

问题是:执行此代码时会发生什么?我们有六个任务; 其中一个将需要一整天才能完成,其余的应该更快完成。毫不奇怪,每次执行代码时,都会得到不同的结果。你想在生产系统中有这样的行为吗?一个杜塞的任务取消了应用程序的其余部分?我猜不会。

关于如何确保永远不会发生这样的事情,只有两种选择。第一个是确保提交到公共fork-join池的所有任务都不会卡,必须在合理的时间内完成。但这说起来容易做起来难,尤其是在复杂的应用程序中。

另一种选择是不使用并行流,并等到Oracle允许我们指定用于并行流的线程池。

Java 8并行流的性能陷阱的更多相关文章

  1. RecursiveTask和RecursiveAction的使用 以及java 8 并行流和顺序流(转)

    什么是Fork/Join框架        Fork/Join框架是Java7提供了的一个用于并行执行任务的框架, 是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架. 我 ...

  2. JAVA使用并行流(ParallelStream)时要注意的一些问题

    https://blog.csdn.net/xuxiaoyinliu/article/details/73040808

  3. java 8新特性 并行流

    使用并行流,提高cpu利用率,提高运算速度 /** * java 8并行流 * 底层运用fork join框架 */ @Test public void test(){ Instant start = ...

  4. Java 8 (6) Stream 流 - 并行数据处理与性能

    在Java 7之前,并行处理集合非常麻烦.首先你要明确的把包含数据的数据结构分成若干子部分,然后你要把每个子部分分配一个独立的线程.然后,你需要在恰当的时候对他们进行同步来避免竞争,等待所有线程完成. ...

  5. 《Java 8 in Action》Chapter 7:并行数据处理与性能

    在Java 7之前,并行处理数据集合非常麻烦.第一,你得明确地把包含数据的数据结构分成若干子部分.第二,你要给每个子部分分配一个独立的线程.第三,你需要在恰当的时候对它们进行同步来避免不希望出现的竞争 ...

  6. java8学习之自定义收集器深度剖析与并行流陷阱

    自定义收集器深度剖析: 在上次[http://www.cnblogs.com/webor2006/p/8342427.html]中咱们自定义了一个收集器,这对如何使用收集器Collector是极有帮助 ...

  7. Java8新特性 并行流与串行流 Fork Join

    并行流就是把一个内容分成多个数据块,并用不同的线程分 别处理每个数据块的流. Java 8 中将并行进行了优化,我们可以很容易的对数据进行并 行操作. Stream API 可以声明性地通过 para ...

  8. JAVA8给我带了什么——并行流和接口新功能

    流,确定是笔者内心很向往的天堂,有他之后JAVA在处理数据就变更加的灵动.加上lambda表达不喜欢都不行.JAVA8也为流在提供另一个功能——并行流.即是有并行流,那么是不是也有顺序流.没有错.我前 ...

  9. list.stream().parallel() 并行流

    https://blog.csdn.net/u011001723/article/details/52794455/  :  parallel()其实就是一个并行执行的流.它通过默认的ForkJoin ...

随机推荐

  1. Zipkin 的 Docker 镜像使用

    1.Zipkin 在 dockerhub 上网址:https://hub.docker.com/r/openzipkin/zipkin 2.下载镜像 docker pull openzipkin/zi ...

  2. Java Excel 导入导出(一)

    本文主要描述通过java实现Excel导入导出 一.读写Excel三种常用方式 1.JXL——Java Excel开放源码项目:读取,创建,更新 2.POI——Apache POI ,提供API给Ja ...

  3. Spring启动,constructor,@PostConstruct,afterPropertiesSet,onApplicationEvent执行顺序

    package com.xx; import javax.annotation.PostConstruct; import javax.annotation.Resource; import org. ...

  4. PHP 判断时间段 至今过了多长时间

    /** * * @param timestamp $time 输入时间 * @return str $str 输入时间与现在时间差的中文 */ function wordTime($time) { / ...

  5. Presto Infrastructure at Lyft

    转载一篇关于 lyft presto 平台建设的实践 Overview Early in 2017 we started exploring Presto for OLAP use cases and ...

  6. Incorrect string value: '获取...' for column 'result' at row 1

    错误详情信息: ### Error updating database. Cause: java.sql.SQLException: Incorrect ### The error may invol ...

  7. 《JAVA程序设计》_第十一周学习总结

    一.学习内容 13.1 URL类 URL类是java.net包中的一个重要的类,URL的实例封装着一个统一资源定位符,使用URL创建对象的应用程序称作客户端程序. 一个URL对象包含的三个基本信息:协 ...

  8. js控制网页窗口一打开就自动全屏

    1.如果不需要开新窗口 在body区加入: <body   onLoad= "javascript:window.resizeTo(screen.availWidth,screen.a ...

  9. vs2010怎么更改调试时使用的浏览器

    在当前网站的起始网页上右击,在右击菜单中选择 浏览方式 步骤阅读 2

  10. Java编程思想之六访问权限控制

    访问控制(或隐藏具体实现)与"最初的实现并不恰当"有关. 访问权限控制的等级,从最大权限到最小权限依次为:public,protected,包访问权限(没有关键字)和private ...