Java,哪个线程是顺序流执行的?

在阅读有关流的文档时,我遇到了以下句子:

  • …试图从行为参数中访问可变状态会给你一个错误的选择…如果你没有同步访问该状态,你就会有数据竞争,因此你的代码被破坏…… [1]

  • 如果行为参数确实有副作用…… [没有]保证在同一个线程中执行同一流管道中“相同”元素的不同操作。 [2]

  • 对于任何给定元素,可以在任何时间以及库选择的任何线程中执行该动作。 [3]

这些句子不区分顺序流和并行流。 所以我的问题是:

  1. 在哪个线程中执行顺序流的管道? 它总是调用线程还是一个可以自由选择任何线程的实现?
  2. 在流是顺序的情况下,哪个线程是forEach终端操作的action参数?
  3. 使用顺序流时是否必须使用任何同步?

  • [1 + 2] https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
  • [3] https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#forEach-java.util.function.Consumer-

  1. Stream的终端操作是阻塞操作。 如果没有并行执行,执行终端操作的线程将运行管道中的所有操作。

定义1.1。 Pipeline是一种链式方法。

定义1.2。 中间操作将最终位于流中的任何位置。 它们返回流对象,不会执行管道中的任何操作。

定义1.3。 终端操作仅位于流的末尾。 他们执行管道。 它们不返回流对象,因此不能在它们之后添加其他Intermidiate操作终端操作

  1. 从第一个解决方案中我们可以得出结论,调用线程将在调用流中的每个元素上的forEach 终端操作中执行action方法。

Java 8向我们介绍了Spliterator接口。 它具有Iterator的function,但也有一组操作可以帮助并行执行和分割任务。

在顺序执行中从原始流调用forEach ,调用线程将调用Spliterator.forEachRemaining方法:

 @Override public void forEach(IntConsumer action) { if (!isParallel()) { adapt(sourceStageSpliterator()).forEachRemaining(action); } else { super.forEach(action); } } 

您可以在我的教程中阅读有关Spliterator更多信息: 第7章:Spliterator

  1. 只要您不改变其中一个流操作中的多个线程之间的任何共享状态(并且它被禁止 – 很快就会解释),当您想要运行并行流时,您不需要使用任何其他同步工具或算法。

流操作如减少使用accumulatorcombiner函数来执行并​​行流。 根据定义,流库禁止变异。 你应该避免它。

并发和并行编程中有很多定义。 我将介绍一组最能为我们服务的定义。

定义8.1。 Cuncurrent编程是使用其他同步算法解决任务的能力。

定义8.2。 并行编程是在不使用其他同步算法的情况下解决任务的能力。

您可以在我的教程中阅读更多相关内容: 第8章:并行流 。