使用非并发数据结构源流的无干扰要求是否意味着我们无法在流管道执行期间更改数据结构元素的状态(此外,我们不能更改源数据结构本身)? (问题1)
在有关non-interference的部分中,在流包描述中,其表示为:
“对于大多数数据源而言,防止干扰意味着确保在流管道执行期间根本不修改数据源。”
这段话没有提到修改元素的状态?
例如,假设“shapes”是非线程安全的集合(例如ArrayList
),那么下面的代码是否被认为具有干扰性? (问题2)
shapes.stream()
.filter(s -> s.getColor() == BLUE)
.forEach(s -> s.setColor(RED));
此示例摘自reliable source(至少可以说),因此它应该是正确的。
但是,如果我将
stream()
更改为parallelStream()
,仍然安全又正确吗? (问题3)另一方面,另一可靠来源Naftalin Maurice的“Mastering Lambdas”清楚地表明,通过管道操作更改元素的状态(值)确实是干扰。在关于无干扰的部分(3.2.3)中:
“但是流规则禁止任何线程对流源进行任何修改,包括例如更改元素的值,而不仅限于管道操作。”
如果书中的说法是正确的,是否意味着我们不能使用Stream API修改元素的状态(使用
forEach
),而必须使用常规迭代器(或for-each或Iterable.forEach
)来做到这一点? (问题4) 最佳答案
还有一类更大的函数,称为“具有副作用的函数”。 JavaDoc语句正确且完整:这里的干扰意味着修改可变源。另一种情况是有状态表达式:依赖于应用程序状态或更改此状态的表达式。您可以阅读Oracle网站上的Parallelism教程。
通常,您可以修改流元素本身,并且不应将其称为“干扰”。请注意,如果流源多次产生相同的可变对象(例如,使用Collections.nCopies(10, new MyMutableObject()).parallelStream()
。)可以确保同一线程元素不会被多个线程同时处理,但是如果流两次产生相同的元素,则可能例如,在forEach
中修改时肯定具有竞争条件。
因此,尽管有状态的表达有时会有些气味,应该谨慎使用,如果有无状态的替代方法,则应避免使用它们,但如果它们不干扰流源,它们可能就可以了。当需要无状态表达式时(例如,在 Stream.map
方法中),API文档中特别提到了它。在forEach
文档中,仅要求无干扰。
回到您的问题:
问题1:不,我们可以更改元素状态,这不称为干扰(尽管称为状态充满度)
问题2:不,除非您在流源中重复对象,否则它没有干扰)
问题3:您可以在那里安全地使用parallelStream()
问题4:不,在这种情况下,您可以使用Stream API。