java - Collection.parallelStream() 是否暗示发生前的关系?
问题描述
考虑这个(完全人为的)Java 代码:
final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
a[0] = 100;
s.parallelStream().forEach(i -> {
synchronized (a) {
a[0] += i;
}
});
System.out.println(a[0]);
此代码是否保证输出“106”?
似乎不是,除非建立了一个happens-before关系parallelStream()
,通过它我们可以确定a[0]
lambda中的第一次访问将看到100
而不是零(根据我对Java内存模型的理解)。
但Collection.parallelStream()
没有记录建立这种关系......
parallelStream()
对于方法调用的完成,可以询问相同的问题。
那么我是否遗漏了一些东西,或者为了正确起见,上面的代码是否需要看起来像这样:
final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
synchronized (a) {
a[0] = 100;
}
s.parallelStream().forEach(i -> {
synchronized (a) {
a[0] += i;
}
});
synchronized (a) {
System.out.println(a[0]);
}
或者......确实parallelStream()
提供了这些发生之前的关系,而这仅仅是缺少一些文档的问题?
我之所以问,是因为从 API 设计的角度来看,这似乎(至少对我而言)是一件合乎逻辑的事情……类似于Thread.start()
等。
解决方案
您确实应该避免在管道“外部”遇到变量。即使你让它正常工作,性能也可能会受到影响。JDK 内置了很多工具来实现这一点。例如,您的用例可能更安全,例如:
Integer reduce = IntStream.of(1, 2, 3)
.parallel()
.reduce(100, (accumulator, element) -> accumulator + element);
推荐阅读
- javascript - Gatsby 错误 [HPM] 尝试将请求 / 从 localhost:8000 代理到 http://localhost:4000 时发生错误(ECONNREFUSED)
- css - 在 Squarespace 上更改一页的背景
- c# - C# Selenium javascript 删除元素不起作用
- react-native - 如何从嵌套的 toptabnavigator 导航到父 StackNavigator?
- rust - Rust 是否正式区分了将编译时检查换成运行时检查的结构?
- python - python中对象和方法的递归
- database - 在 Couchbase 中使用 N1QL 从对象对象中获取所有唯一键
- python - 将 LIVE SPEECH 与 Tkinter GUI 连接
- machine-learning - 如何在分类中获取类名?
- javascript - 从两个字段计算值并显示在 JavaScript 的第三个字段中