规范是否保证顺序Java流上的操作必须保留在当前线程中?

时间:2018-05-23 14:46:38

标签: java java-8 java-stream thread-local

规范是否保证在顺序 Java Streams上的所有操作都在当前线程中执行? (“forEach”和“forEachOrdered”除外)

我明确要求规范,而不是当前的实现。我可以自己查看当前的实现,不需要打扰你。但实现可能会改变,还有其他实现。

我问因为ThreadLocals:我使用的是一个在内部使用ThreadLocals的框架。即使像company.getName()这样的简单调用最终也会使用ThreadLocal。我无法改变该框架的设计方式。至少不在理智的时间内。

这里的规范似乎令人困惑。 the Package "java.util.stream"州的文件:

  

如果行为参数确实有副作用,除非明确说明,否则不能保证这些副作用对其他线程的可见性,也不保证对“相同”的不同操作同一个流管道中的元素在同一个线程中执行

     

...

     

即使管道被约束产生的结果与流源的遭遇顺序一致(例如,IntStream.range(0,5).parallel()。map(x - > x * 2 ).toArray()必须生成[0,2,4,6,8]),不保证关于mapper函数应用于单个元素的顺序,或对于给定元素,在什么线程中执行任何行为参数

我会将其解释为:流上的每个操作都可以在不同的线程中进行。但the documentation of "forEach" and "forEachOrdered"明确指出:

  

对于任何给定元素,可以在任何时间以及库选择的任何线程中执行操作。

如果每个流操作都可能发生在未指定的线程中,那么该语句将是多余的。因此情况恰恰相反:串行流上的所有操作都保证在当前线程中执行,“forEach”和“forEachOrdered”除外?

我搜索了关于“Java”,“Stream”和“ThreadLocal”组合的权威答案,但没有发现任何内容。关闭的事情是Brian Goetz对Stack Overflow上的相关问题的回答,但它是关于顺序而不是线程,它只是关于“forEach”,而不是其他流方法:{{3 }}

1 个答案:

答案 0 :(得分:1)

我相信你所寻找的答案并没有那么明确,因为它取决于消费者和/或分裂者及其特征:

在阅读主要报价之前:

https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#stream

  

default Stream stream()返回一个顺序Stream   集合作为其来源。当这个方法应该被覆盖   spliterator()方法无法返回一个IMMUTABLE的spliterator,   CONCURRENT或后期绑定。 (有关详细信息,请参阅spliterator()。)

https://docs.oracle.com/javase/8/docs/api/java/util/Spliterator.html#binding

  

尽管它们在并行算法中具有明显的实用性,但分裂器却是如此   不期望是线程安全的;相反,并行的实现   使用分裂器的算法应该确保分裂器   仅一次由一个线程使用。这通常很容易实现   通过串行线程限制,这通常是自然的结果   通过递归分解工作的典型并行算法。一个   线程调用trySplit()可能会将返回的Spliterator移交给   另一个线程,反过来可能会遍历或进一步分裂   Spliterator。如果,则拆分和遍历的行为是不确定的   两个或多个线程在同一个分裂器上同时运行。如果   原始线程将分裂器移交给另一个线程   处理,最好是在任何元素出现之前进行切换   与tryAdvance()一起使用,作为某些保证(例如   SIZED分裂器的estimateSize()的准确性仅有效   在遍历开始之前。

Spliterators和消费者具有一系列特征,这将定义保证。假设您正在进行操作。因为spliterators不应该是线程安全的并且应该处理可能在其他线程中的其他分裂器的元素,无论是否是顺序的,所以保证为null。但是,如果没有拆分occor,引号将导致以下内容:在一个spliterator下,操作将保留在同一个线程中,任何导致拆分的事件都将导致假设为null,否则为true