Java 8 流中的不干扰确切含义

2022-01-22 00:00:00 lambda java-8 java java-stream

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

Does the non-interference requirement for using streams of non-concurrent data structure sources mean that we can't change the state of an element of the data structure during the execution of a stream pipeline (in addition to that we can't change the source data structure itself)? (Question 1)

在关于 的部分中不干扰,在流包描述中,它说:对于大多数数据源而言,防止干扰意味着确保在流管道执行过程中完全不修改数据源."

In the section about non-interference, in the stream package description, its said: "For most data sources, preventing interference means ensuring that the data source is not modified at all during the execution of the stream pipeline."

这段没有提到修改元素的状态?

This passage does not mention modifying the state of elements?

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

For example, assuming "shapes" is non-thread-safe collection (such as ArrayList), is the code below considered to have an interference? (Question 2)

shapes.stream() 
      .filter(s -> s.getColor() == BLUE)
      .forEach(s -> s.setColor(RED));

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

This example is taken from a reliable source (to say the least), so it should be correct. But what if I changed stream() to be parallelStream(), will it still be safe and correct? (Question 3)

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

On the other hand, "Mastering Lambdas" by Naftalin Maurice, another reliable source, makes it clear that changing the state (value) of elements by the pipeline operation is indeed interference. From the section about non-interference (3.2.3):

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

"But the rules for streams forbid any modification of stream sources—including, for example, changing the value of an element— by any thread, not only pipeline operations."

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

If what's said in the book is correct, does it mean we can't use the Stream API to modify state of elements (using forEach), and have to do that using the regular iterator (or for-each, or Iterable.forEach)? (Question 4)

推荐答案

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

There's a bigger class of functions called "functions with side effects". The JavaDoc statement is correct and complete: here interference means modifying the mutable source. Another case is stateful expressions: expressions which depend on the application state or change this state. You may read the Parallelism tutorial on Oracle site.

一般来说,你可以自己修改流元素,它不应该被称为干扰".但请注意,如果流源多次生成相同的可变对象(例如,使用 Collections.nCopies(10, new MyMutableObject()).parallelStream().虽然可以确保相同流元素不是由多个线程同时处理的,如果你的流产生了两次相同的元素,那么在 forEach 中修改它时肯定会出现竞争条件.

In general you can modify the stream elements themselves and it should not be called as "interference". Beware though if you have the same mutable object produced several times by the stream source (for example, using Collections.nCopies(10, new MyMutableObject()).parallelStream(). While it's ensured that the same stream element is not processed concurrently by several threads, if your stream produces the same element twice, you may surely have a race condition when modifying it in the forEach, for example.

因此,虽然有状态的表达式有时很臭,如果有无状态的替代方案,应该小心使用并避免使用,但如果它们不干扰流源,它们可能没问题.当需要无状态表达式时(例如,在 Stream.map 方法),API 文档中特别提到.在 forEach 文档中只需要不干涉.

So while stateful expressions are sometimes smell and should be used with care and avoided if there's a stateless alternative, they are probably ok if they don't interfere with the stream source. When the stateless expression is required (for example, in Stream.map method), it's specially mentioned in the API docs. In forEach documentation only non-interference is required.

回到你的问题:

问题1:不,我们可以改变元素的状态,这不叫干扰(虽然叫statefullness)

Question 1: no we can change the element state, and it's not called interference (though called statefullness)

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

Question 2: no it has no interference unless you have repeating objects in your stream source)

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

Question 3: you can safely use parallelStream() there

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

Question 4: no, you can use Stream API in this case.

相关文章