Java - 连续并行流之间的缓存一致性?
考虑下面的代码段(乍一看并不完全相同)。
static class NumberContainer {
int value = 0;
void increment() {
value++;
}
int getValue() {
return value;
}
}
public static void main(String[] args) {
List<NumberContainer> list = new ArrayList<>();
int numElements = 100000;
for (int i = 0; i < numElements; i++) {
list.add(new NumberContainer());
}
int numIterations = 10000;
for (int j = 0; j < numIterations; j++) {
list.parallelStream().forEach(NumberContainer::increment);
}
list.forEach(container -> {
if (container.getValue() != numIterations) {
System.out.println("Problem!!!");
}
});
}
我的问题是:为了绝对确定不会打印“问题!!!”,数字容器类中的“value”变量是否需要标记为易失性?
让我解释一下我目前是如何理解这一点的。
在第一个并行流中,NumberContainer-123(比如说)由ForkJoinWorker-1(比如说)递增。因此,ForkJoinWorker-1 将具有 NumberContainer-123.value 的最新缓存,即 1。(但是,其他分叉连接工作线程将具有 NumberContainer-123.value 的过期缓存 - 它们将存储值 0。在某些时候,这些其他工作线程的缓存将被更新,但这不会立即发生。
第一个并行流完成,但不会终止常见的分叉连接池工作线程。然后,第二个并行流启动,使用完全相同的常见分叉连接池工作线程。
现在,假设在第二个并行流中,递增NumberContainer-123的任务分配给ForkJoinWorker-2(例如)。ForkJoinWorker-2 将有自己的缓存值 NumberContainer-123.value。如果在 NumberContainer-123 的第一个和第二个增量之间经过了很长一段时间,那么推测 ForkJoinWorker-2 的 NumberContainer-123.value 缓存将是最新的,即值 1 将被存储,一切都很好。但是,如果 NumberContainer-123 非常短,那么在第一个和第二个增量之间经过的时间会怎样呢?然后,也许ForkJoinWorker-2的NumberContainer-123.value缓存可能已过期,存储值0,导致代码失败!
我上面的描述是否正确?如果是这样,任何人都可以告诉我,为了保证线程之间的缓存一致性,两个递增操作之间需要什么样的时间延迟?或者,如果我的理解是错误的,那么有人可以告诉我是什么机制导致线程本地缓存在第一个并行流和第二个并行流之间被“刷新”?