使用非并发数据结构源流的非干扰要求是否意味着我们无法在执行流管道期间更改数据结构的元素的状态(除此之外,我们无法改变源数据结构本身)? (问题1)
在关于non-interference的部分中,在流包描述中,它说: “对于大多数数据源,防止干扰意味着在流管道执行期间确保数据源不会被修改。”
这段经文没有提到修改元素的状态?
例如,假设“形状”是非线程安全的集合(例如ArrayList
),下面的代码是否被视为干扰? (问题2)
shapes.stream()
.filter(s -> s.getColor() == BLUE)
.forEach(s -> s.setColor(RED));
此示例取自reliable source(至少可以说),因此它应该是正确的。
但是,如果我将stream()
更改为parallelStream()
,它仍然是安全和正确的吗? (问题3)
另一方面,另一个可靠来源Naftalin Maurice的“掌握Lambdas”清楚地表明,通过管道操作改变元素的状态(值)确实是干扰。从关于不干涉的部分(3.2.3):
“但是流规则禁止对流源进行任何修改 - 包括,例如,通过任何线程更改元素的值,而不仅仅是管道操作。”
如果书中所说的是正确的,是否意味着我们不能使用Stream API来修改元素的状态(使用forEach
),并且必须使用常规迭代器(或者为 - )每个,或Iterable.forEach
)? (问题4)
答案 0 :(得分:8)
有一类更大的功能称为"具有副作用的功能"。 JavaDoc语句是正确和完整的:这里干扰意味着修改可变源。另一种情况是有状态表达式:依赖于应用程序状态或更改此状态的表达式。您可以阅读Oracle网站上的Parallelism教程。
通常,您可以修改流元素本身,不应将其称为" interference"。请注意,如果流源有多次生成相同的可变对象(例如,使用 try {
dbConnection = getDBConnection();
dbConnection.setAutoCommit(false);
// do your database work preparedStatement Insert, Update
//OR
// If you are doing your work on DAO you can pass connection to your DAO
//XDao xDao = new XDao(dbConnection);
//YDao yDao = new YDao(dbConnection);
//xDao.doWork();
//yDao.doWork()
dbConnection.commit();
System.out.println("Done!");
} catch (SQLException e) {
System.out.println(e.getMessage());
dbConnection.rollback();
} finally {
//Close prepared statements
//close connection
if (dbConnection != null) {
dbConnection.close();
}
}
。虽然它确保多个线程不会同时处理相同的流元素,但是如果您的流两次生成相同的元素,例如,在Collections.nCopies(10, new MyMutableObject()).parallelStream()
中修改它时,肯定会遇到竞争条件。
因此,虽然有状态的表达有时会闻到并且应该谨慎使用,如果有无状态替代方案,则应避免使用它们,如果它们不干扰流源,它们可能就可以了。当需要无状态表达式时(例如,在Stream.map
方法中),它在API文档中特别提到。在forEach
文档中,只需要不干涉。
回到你的问题:
问题1:我们不能改变元素状态,并且它不被称为干扰(虽然称为状态完整性)
问题2:除非你的流源中有重复的对象,否则它没有干扰)
问题3:您可以安全地使用forEach
问题4:不,你可以在这种情况下使用Stream API。
答案 1 :(得分:1)
修改存储在数据结构中的对象的状态与重新分配数据结构的元素不同。
当另一个写“改变元素的值”时,他们可能意味着将新对象分配给现有List
的索引。
来自link:
最好避免传递给流方法的lambdas中的任何副作用。虽然一些副作用(例如打印输出值的调试语句)通常是安全的,但是从这些lambdas访问可变状态会导致数据争用或令人惊讶的行为,因为lambdas可能同时从多个线程执行,并且可能在其自然遭遇中看不到元素订购。不干涉不仅包括干扰源,而且不干扰其他lambda;当一个lambda修改可变状态而另一个lambda读取它时,会产生这种干扰。
只要满足非干扰要求,即使在非线程安全的源(如ArrayList)上,我们也可以安全地执行并行操作并获得可预测的结果。
这特别适用于并行性,与任何其他并发编程没有什么不同。修改状态可能会导致线程之间的可见性问题。