Arc*_*hie 6 java java-memory-model java-stream
考虑这个(完全人为的)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]);
Run Code Online (Sandbox Code Playgroud)
此代码是否保证输出"106"?
似乎不存在,除非有一个先发生过的关系建立起来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]);
}
Run Code Online (Sandbox Code Playgroud)
或者...... parallelStream()实际上提供了这些发生在之前的关系,这只是一些遗漏文档的问题?
我问,因为从API设计的角度来看,似乎(至少对我来说)这样做是合乎逻辑的......类似于Thread.start()等等.
以下是建立先行发生关系的操作列表。正如您所看到的parallelStream,那里没有提到,所以回答您的问题:不,
parallelStream它本身并没有建立先发生的关系。
至于第一次访问读数为零 - 如果主线程在parallelStream处理之前设置 100,则paralleStream启动的每个线程都会看到该值,引用链接:
对线程启动的调用发生在已启动线程中的任何操作之前。
顺便说一句,你的 lambda 表达式的使用是有状态的,这是不鼓励的