Java 8流中的非干扰精确含义

Sha*_*hay 10 java lambda java-8 java-stream

使用非并发数据结构源流的非干扰要求是否意味着在执行流管道期间我们无法更改数据结构元素的状态(除此之外我们无法更改源数据结构本身)?(问题1)

在关于非干扰的部分中,在流包描述中,它说:"对于大多数数据源,防止干扰意味着确保在流管道的执行期间根本不修改数据源."

这篇文章没有提到修改元素的状态?

例如,假设"形状"是非线程安全的集合(例如ArrayList),下面的代码是否被认为有干扰?(问题2)

shapes.stream() 
      .filter(s -> s.getColor() == BLUE)
      .forEach(s -> s.setColor(RED));
Run Code Online (Sandbox Code Playgroud)

这个例子取自可靠的来源(至少可以说),所以它应该是正确的.但是,如果我改变stream()parallelStream(),它仍然是安全和正确的吗?(问题3)

另一方面,另一个可靠来源Naftalin Maurice的"掌握Lambdas"清楚地表明,通过管道操作改变元素的状态(值)确实是干扰.从关于不干涉的部分(3.2.3):

"但是流的规则禁止对流源进行任何修改 - 包括,例如,通过任何线程更改元素的值,而不仅仅是管道操作."

如果书中所说的是正确的,是否意味着我们不能使用Stream API来修改元素的状态(使用forEach),并且必须使用常规迭代器(或for-each,或Iterable.forEach)来做到这一点?(问题4)

Tag*_*eev 8

有一类更大的函数叫做"带副作用的函数".JavaDoc语句是正确和完整的:这里干扰意味着修改可变源.另一种情况是有状态表达式:依赖于应用程序状态或更改此状态的表达式.您可以阅读Oracle站点上的Parallelism教程.

通常,您可以修改流元素本身,不应将其称为"干扰".请注意,如果你有相同的可变对象由流源生成多次(例如,使用Collections.nCopies(10, new MyMutableObject()).parallelStream().虽然确保相同的流元素不会被多个线程同时处理,但如果你的流生成相同的元素两次,你肯定可以在修改它时有一个竞争条件forEach例如,.

因此,虽然有状态表达式有时会有气味,但如果有无状态替代方案,则应谨慎使用并避免使用,如果它们不干扰流源,则它们可能正常.当需要无状态表达式时(例如,在Stream.map方法中),它在API文档中特别提到.在forEach文档中,只需要不干涉.

回到你的问题:

问题1:不,我们可以改变元素状态,它不称为干扰(虽然称为状态完整性)

问题2:除非你的流源中有重复的对象,否则它没有干扰)

问题3:你可以安全地parallelStream()在那里使用

问题4:不,在这种情况下您可以使用Stream API.

  • 换句话说,"干扰"生活在更高层次上.修改流元素的操作可能会在同时修改同一元素时发生干扰,但在修改不同对象时则不会.类似地,"ArrayList"本身不是线程安全的并不排除在并发场景中正确使用ArrayList的可能性.它是关于,*如何使用它...... (3认同)