limit操作与无序流的内部变更及Java并行流代码疑问
关于并行无限流中peek与limit的行为解析
嘿,这个问题挺有代表性的,咱们来唠唠这段代码里count结果为啥不一定是5~
首先得理清几个关键知识点:
IntStream.generate(() -> i.incrementAndGet())是无序的无限流:它没有固定的元素生成顺序,而且会一直生成元素直到流终止。在并行模式下,多个线程会各自独立生成元素,不会互相等待。limit(5)是短路终止操作,但并行场景下的逻辑和串行完全不同:串行流里,拿到第5个元素就会立刻停止生成新元素;但并行流为了提升效率,会让各个线程提前生成一批元素(类似预取),哪怕最后只需要5个,有些线程已经生成的多余元素也会流经peek环节。peek(x -> count.incrementAndGet())的特性:peek会对所有流经它的元素执行操作,不管这个元素最终会不会被limit筛选出来保留。也就是说,只要元素被生成并进入了流的处理管道,哪怕最后没被forEach输出,count也会自增。
举个实际场景的例子:
假设JVM启动了2个线程处理这个并行流:
- 线程1生成了元素1、2,然后把它们传给后续环节
- 线程2生成了3、4、5、6,这时候
limit(5)已经收集到足够的元素,会终止流,但线程2生成的6已经走到了peek步骤,所以count会被自增到6,而最终forEach只输出1-5这5个元素。
另外要说明的是,这里用AtomicInteger是完全正确的,不存在线程安全问题,count的数值准确反映了所有被peek处理过的元素总数,只是这个总数会因为并行流的预取特性,必然大于等于limit指定的5。
内容的提问来源于stack exchange,提问作者Eugene
相关产品推荐
相关产品推荐

