Java8 parallelStream浅析

java8 并行流 parallelStream,在8核的机器上,启动了几个线程 java8 并行流 parallelStream,其实就是java集合接口Collection新增的一个方法。 default Stream<E> parallelStream() { return StreamSupport.stream(this.spliterator(), true); } parallelStream的存在,使得处理集合多了一种选择。parallelStream的底层实现, 并没有多么高大上的技术,而是我们熟知的多线程框架ForkJoin。 .. 阅读详情

JAVA8中引入了lamda表达式和Stream接口。其丰富的API及强大的表达能力极大的简化代码,提升了效率,同时还通过parallelStream提供并发操作的支持,本文探讨parallelStream方法的使用。

首先看下java doc中对parallelStream的定义。

  A sequence of elements supporting sequential and parallel aggregate operations.
 ...
 Stream pipelines may execute either sequentially or in parallel. This execution mode is a property of the stream. Streams are created with an initial choice of sequential or parallel execution. (For example, Collection.stream() creates a sequential stream, and Collection.parallelStream() creates a parallel one.) This choice of execution mode may be modified by the BaseStream.sequential() or BaseStream.parallel() methods, and may be queried with the BaseStream.isParallel() method.

既然可以并行的执行,废话不多说,先看一个例子。

class Person {
        int    id;
        String name;
        String sex;
        float  height;

        public Person(int id, String name, String sex, float height) {
            this.id = id;
            this.name = name;
            this.sex = sex;
            this.height = height;
        }
}

    /**
     * 构造数据
     * 
     * @return
     */
    public List<Person> constructPersons() {

        List<Person> persons = new ArrayList<Person>();
        for (int i = 0; i < 5; i++) {
            Person p = new Person(i, "name" + i, "sex" + i, i);
            persons.add(p);
        }
        return persons;
    }

    /**
     * for
     * 
     * @param persons
     */
    public void doFor(List<Person> persons) {
        long start = System.currentTimeMillis();

        for (Person p : persons) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(p.name);
        }

        long end = System.currentTimeMillis();
        System.out.println("doFor cost:" + (end - start));
    }

    /**
     * 顺序流
     * 
     * @param persons
     */
    public void doStream(List<Person> persons) {
        long start = System.currentTimeMillis();

        persons.stream().forEach(x -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(x.name);
        });

        long end = System.currentTimeMillis();
        System.out.println("doStream cost:" + (end - start));
    }

    /**
     * 并行流
     * 
     * @param persons
     */
    public void doParallelStream(List<Person> persons) {

        long start = System.currentTimeMillis();

        persons.parallelStream().forEach(x -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
            System.out.println(x.name);
        });

        long end = System.currentTimeMillis();

        System.out.println("doParallelStream cost:" + (end - start));
    }

执行结果:

 public static void main(String[] args) {
         Person person=new Person();
         List<Person> list=person.constructPersons();
         new Thread(()->{
             person.doStream(list);
         }).start();



         new Thread(()->{
             person.doParallelStream(list);
         }).start();



         new Thread(()->{
             person.doFor(list);
         }).start();
       }
}
for name0
doStream name0
doParallelStream name2
doParallelStream name4
doParallelStream name1
doParallelStream name0
doParallelStream name3
doParallelStream cost:1007
for name1
doStream name1
for name2
doStream name2
for name3
doStream name3
for name4
doFor cost:5000
doStream name4
doStream cost:5003

代码上 stream 和 parallelStream 语法差异较小,从执行结果来看,stream顺序输出,而parallelStream 无序输出;parallelStream 执行耗时是 stream 的五分之一。
可以看到在当前测试场景下,parallelStream 获得的相对较好的执行性能,那parallelStream背后到底是什么呢?
要深入了解parallelStream,首先要弄明白ForkJoin框架和ForkJoinPool。ForkJoin框架是java7中提供的并行执行框架,他的策略是分而治之。说白了,就是把一个大的任务切分成很多小的子任务,子任务执行完毕后,再把结果合并起来。

顺便说下ForkJoin框架和ThreadPoolExecutor的区别,ForkJoin框架可以使用数量有限的线程数,执行大量任务,并且这些任务之间是有父子依赖的,必须是子任务执行完成后,父任务才能执行。ThreadPoolExecutor 显然是无法支持这种场景的。而ForkJoin框架,可以让其中的线程创建新的任务,并挂起当前的任务,任务以及子任务会保留在一个内部队列中,此时线程就能够从队列中选择任务顺序执行。

Java 8为ForkJoinPool添加了一个通用线程池,这个线程池用来处理那些没有被显式提交到任何线程池的任务。它是ForkJoinPool类型上的一个静态元素,它拥有的默认线程数量等于运行计算机上的处理器数量。当调用Arrays类上添加的新方法时,自动并行化就会发生。比如用来排序一个数组的并行快速排序,用来对一个数组中的元素进行并行遍历。自动并行化也被运用在Java 8新添加的Stream API中。

上面的代码中,forEach方法会为每个元素的操作创建一个任务,该任务会被前文中提到的ForkJoinPool中的通用线程池处理。以上的并行计算逻辑当然也可以使用ThreadPoolExecutor完成,但是就代码的可读性和代码量而言,使用ForkJoinPool明显更胜一筹。

默认线程池的数量就是处理器的数量,特殊场景下可以使用系统属性:-Djava.util.concurrent.ForkJoinPool.common.parallelism={N} 调整。

doParallelStream耗时最多,可见并不是并行执行就是性能最好的,要根据具体的应用场景测试分析。这个例子中,每个子任务执行时间较短,而线程切换消耗了大量时间。

说到了并发,不得不提线程安全。先看一个例子:

public void doThreadUnSafe() {
        List<Integer> listFor = new ArrayList<>();
        List<Integer> listParallel = new ArrayList<>();

        IntStream.range(0, 1000).forEach(listFor::add);
        IntStream.range(0, 1000).parallel().forEach(listParallel::add);

        System.out.println("listFor size :" + listFor.size());
        System.out.println("listParallel size :" + listParallel.size());
    }


输出结果:

listFor size :1000
listParallel size :949

显而易见,stream.parallel.forEach()中执行的操作并非线程安全。如果需要线程安全,可以把集合转换为同步集合,即:Collections.synchronizedList(new ArrayList<>())。

总结下来如下:

  1. 使用parallelStream可以简洁高效的写出并发代码。
  2. parallelStream并行执行是无序的。
  3. parallelStream提供了更简单的并发执行的实现,但并不意味着更高的性能,它是使用要根据具体的应用场景。如果cpu资源紧张parallelStream不会带来性能提升;如果存在频繁的线程切换反而会降低性能。
  4. 任务之间最好是状态无关的,因为parallelStream默认是非线程安全的,可能带来结果的不确定性。

参考:

https://zhuanlan.zhihu.com/p/43039062

Java8中并行化流parallel的使用 前面讲Stream的常用api的使用,在处理一些集合数据时很方便,但是在执行一些耗时或是占用资源很高的任务的时候,串行化的流无法带来速度/性能上的提升,除了使用多线程来并行执行任务之外,Stream中也提供了这样的方法。parallelStream()方法或者是使用stream().parallel()来转化为并行流。 阅读详情

相关推荐

ADI恒流驱动芯片LT3763调试心得(25A恒流驱动)

看似很简单的一个电路,调了好几版硬件,中间还出现过一个插曲,就是电感,我用的是27A,1.5uH的,贴片封装,由于频繁试板,电感来回用热风枪拆了3次,结果上电空载到3A都没有问题,但是以上10A以上,就出现烧LT3763和mos的情况,一连烧了8片,搞得有点怀疑人生,一度觉得我的电路设计有问题,邮件咨询ADI的FAE后,确认电路设计没有问题。1、大功率同步整流的Nmos管都是取不同的型号,就是厂家推荐的主开关管和续流管的型号往往都不一样,这个里面有什么讲究,我没有整明白,暂时也不需要弄明白。

liming98lm的博客 3922

Java8 遍历List 使用stream().parallel()并发安全

引入了并行流的概念来进行并行处理,而并行流(Parallel Stream)利用所有可用CPU内核的优势,并并行处理任务。其原理(Parallel Stream)是可以把大任务分成多个小任务执行, 最后再把执行结果进行合并, ForkJoinPool用工作窃取算法实现。

qiaobing1226的博客 8193

无法找到来自源 nvlddmkm 的事件 ID 14 的描述

具体错误是: 无法找到来自源 nvlddmkm 的事件 ID 14 的描述。本地计算机上未安装引发此事件的组件,或者安装已损坏。可以安装或修复本地计算机上的组件。 出现这样错误的原因有很多了,有可能是硬件有可能是软件。由于我是刚配置的电脑,起初非常怀疑是自己组装的问题,折腾了好久,心态爆炸!!!先说我报这样错误的情况,以及解决办法,供后面人参考。 ...

SeventhBlue 6万+

通过线程池方式改造Stream.parallel()并行流

大家好,我是哪吒。上一篇简单聊一聊公平锁和非公平锁,parallel并行流,提到了一个IntStream.rangeClosed并行流问题,很多小伙伴,对这个比较陌生,想用线程池的方式改造一下。 二、线程池方式改造 不会那些新特性,还是原始的香啊,写起代码,得心应手。这时候,有些小伙伴,又陷入了选择恐惧症。用哪个线程池比较好呢?简单回顾一下:最常用的还是固定线程数线程池newFixedThreadPool(10)。 2、线程类 3、信心满满,走起来 我草,这不对啊,不应该是100000嘛?又把老子整不会了

学Java,找哪吒 2781

World Action Model:经典论文

郑困时,图prorpt为机量人压务时,退过驱制解弱词表(constrsinsd decoding), 强附模型只从.256个者动作token中保H, B象总注活地。始VLA之一,RT-2使用了大量的五联网VQ据与少里的机械网的AcSonDat行CoFine-Tunng, 独组sl, 共i744个episode,Mous使用三个专累模,分是vidogonmedel,actonesget,understandng。包的核定之的的观到沟血黄动作,预之后现(vorlemodel),tseing,2。

u013250861的博客 410

OpenWrt虚拟机磁盘扩容实战:从SquashFS到ext4的完整避坑指南

本文详细介绍了OpenWrt虚拟机磁盘扩容的完整流程,重点对比了SquashFS和ext4文件系统在扩容操作上的关键差异。通过五步安全迁移法和直接分区调整方案,帮助用户有效解决磁盘空间不足问题,同时提供高级技巧和故障排除指南,确保扩容过程顺利无坑。

weixin_29251131的博客 232

java8 IntStream.range

IntStream.range是Java 8中的一个方法,它是java.util.stream.IntStream类中的静态方法。这个方法用于生成一个顺序排列的整数流,包含起始值但不包含结束值。startInclusive是生成整数流的起始值(包含),endExclusive是生成整数流的结束值(不包含)//业务处理总的来说就相当于i++)只是转换为java8 stream的写法,也可以调用一些stream方法,写起来会简便,但是可读性自然而然的变差,也要考虑使用的场景。​。

max_xujw的博客 3338

Xilinx Vitis HLS教程1--Vitis HLS概述[01/12]

Xilinx Vitis HLS教程[01/10]前言1. Vitis HLS简介1.1 软件工程师的设计原则1.1.1 简介1.1.2 吞吐量和性能1.2.3 架构问题1.2.4 FPGA编程的3大范式1.2.4.1 生产者-消费者范式1.2.4.2 流式数据范式1.2.4.3 流水线范式1.2.5 3种范式结合 前言 项目中使用到Xilinx Zynq UltraScale+ MPSoC ZCU102 开发板,领导指示研究"xilinx软件自带的c语言综合器"。对于一个硬件一窍不通的我来说,甚至不知道

B10030607的博客 5241

关于并行流parallelStream的用法的一些问题

前言 今天逛论坛关于parallelStream并行流一些内容,发现论坛里关于这方面的问题,他们给出的代码是这样的 @Test public void testStream() { List<Integer> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { list.add(i); } System.out.println(list.size()); ...

GoodIdea 640

CONN工具箱分析fmri数据笔记1

前言一、安装二、预处理三、去噪 前言 CONN:functional connectivity toolbox,是基于MATLAB和SPM的一个对功能磁共振数据进行分析的一个工具箱。可以进行以下分析: Seed-based correlations (SBC), ROI-to-ROI correlations, graph analyses, Independent component analyses(group-ICA), Masked (ICA) Amplitude of Low-Frequency.

weixin_52073820的博客 6587

13、无人机网络安全攻击检测:入侵检测系统综述

本文综述了无人机网络(FANETs)中的网络安全攻击与入侵检测系统(IDS)研究进展。文章介绍了无人机网络的架构设计、路由协议分类及移动模型,重点分析了DoS、DDoS、病毒蠕虫和零日攻击等常见安全威胁,并系统梳理了网络型、主机型、签名型、异常型、混合型等多种IDS的技术原理与应用。通过对比不同攻击类型及其检测机制,提出了综合使用多类IDS、更新签名库、优化路由、加强加密和建立应急响应等安全防护建议。同时展望了人工智能、量子安全和融合安全架构等未来发展趋势,旨在为提升无人机网络的安全性提供全面的技术参考。

wasm7browser的博客 162

java parallelstream_Java8 parallelStream浅析

JAVA8中引入了lamda表达式和Stream接口。其丰富的API及强大的表达能力极大的简化代码,提升了效率,同时还通过parallelStream提供并发操作的支持,本文探讨parallelStream方法的使用。首先看下java doc中对parallelStream的定义。A sequence of elements supporting sequential and parallel a...

weixin_36174245的博客 328

手把手教你用ESP32-C3打造智能聊天机器人-立创实战派

本文将详细介绍如何利用立创ESP32-C3开发板,烧录小智AI程序,快速实现一个功能强大的聊天机器人。

举世誉之而不加劝,举世非之而不加沮,定乎内外之分,辩乎荣辱之境,斯已矣。 5542

java基础总结(七十)--Java8中的parallelStream的坑

about Stream 什么是流? Stream是java8中新增加的一个特性,被java猿统称为流. Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大...

秋天的猿 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

深入浅出parallelStream

about Stream什么是流? Stream是java8中新增加的一个特性,被java猿统称为流. Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 1

梦铃之境的专栏 10万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Stream和parallelStream

Stream 和 parallelStream ParallelStream stream parallelstream stream和parallelStream 一.什么是Stream? Stream 是在 Java8 新增的特性,普遍称其为流;它不是数据结构也不存放任何数据,其主要用于集合的逻辑处理。 二.和Iterator的区别 Iterator 做为迭代器,其按照一定的顺序迭代遍历集合中的每一个元素,并且对每个元素进行指定的操作。

记录成长,分享收获。 13万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Java中parallelStream的使用

前言: 各位读者们好久不见,最近博主我一直在实习中, 而且也准备校招,刷了很多很多的题目,今天在实习中看到了师兄写的代码中使用到了parallelStream()这个并行流计算,所以我想写一篇博客总结一下这个parallelStream新特性的具体使用。 1、什么是parallelStream? 众所周知,stream流式计算是Java8中新添的一种新特性,可以把stream流理解为串行的流式计算,而parallelStream是一种多线程并行流式计算。 2、parallelStream的作用在哪?或者说有

小贱贱的博客 1万+

Java8 并行流(parallelStream)原理分析及注意事项

众所周知,Java 使用Stream流做多线程处理是非常方便的。随着并行编程越来越流行,Java从1.7就开始提供了Fork/Join 支持并行处理,并且在1.8版本进一步加强了相关功能。并行处理就是将任务拆分子任务,分发给多个处理器同时处理之后进行合并。本文将会对并行流(parallelStream)原理分析及注意事项进行详细介绍。

Clearlove_S7的博客 3万+

谈谈并行流parallelStream

一、parallelStream内部使用了哪些线程 Java8中提供了能够更方便处理集合数据的Stream类,其中parallelStream()方法能够充分利用多核CPU的优势,使用多线程加快对集合数据的处理速度。不熟悉Stream类的同学,可以先参考我的另外一篇文章Java8中Stream的常用方法 以一个简单的例子,来看看parallelStream内部到底使用了哪些线程 Integer[] array = new Integer[]{1, 2, 3, 4, 5};

阳阳的博客 3万+

Java8新特性之parallelStream详解

一、什么是流? Stream是java8中新增加的一个特性,首先Stream 不是集合元素,它不是数据结构并不保存数据,它是有关算法和计算的,它更像一个高级版本的 Iterator。原始版本的 Iterator,用户只能显式地一个一个遍历元素并对其执行某些操作;高级版本的 Stream,用户只要给出需要对其包含的元素执行什么操作,比如 “过滤掉长度大于 10 的字符串”、“获取每个字符串的首字母...

lixinkuan的博客 4433

Java8中的Stream()与ParallelStream()的区别

Stream 无状态:指元素的处理不受之前元素的影响; 有状态:指该操作只有拿到所有元素之后才能继续下去。 非短路操作:指必须处理所有元素才能得到最终结果; 短路操作:指遇到某些符合条件的元素就可以得到最终结果,如 A || B,只要A为true,则无需判断B的结果。 ParallelStream 对于ParallelStream,需要知道的是里面的执...

No8g攻城狮的博客 9728

Java8使用ParallelStream注意事项

Java8并行流ParallelStream和Stream的区别就是支持并行执行,提高程序运行效率。但是如果使用不当可能会发生线程安全的问题。Demo如下: public static void concurrentFun() { List<Integer> listOfIntegers = new ArrayList<>...

穷水叮咚的博客 1万+

java中Stream、ParallelStream和ForkjoinPool

Stream、ParallelStream和ForkjoinPool简述 stream是java8开始引入的流式编程 parallelStream是在流式编程的基础上并行化流水线上可以并行化的部分(StatelessOp) fork-join-pool是parallelStream并行化的底层框架,是独立于ThreadPool的多线程并行模型。 三者虽然在功能上关系紧密,但掌握他们要了解的东西却互相独立 A Stream的原理 A.深入理解Java8中Stream的实现原理_lcgoing.

city1993的博客 2582
上一篇: java中stream处理
下一篇: spring boot 连接redis报错
疯信子To
博客等级 码龄14年 12粉丝 42原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值