【发布时间】:2020-02-08 02:21:08
【问题描述】:
如何确保工作线程完成以下代码中的流处理后,即(*)点处,strValues数组的内容是一致的,即(*)处的主线程确实在任何strValues 数组条目中都没有看到陈旧的null 值?
int N = 50;
String[] strValues = new String[N];
IntStream.range(0, N)
.parallel()
.forEach(i -> strValues[i] = Integer.toString(i));
// (*) Is strValues consistent here?
for (String strValue : strValues) {
System.out.println(strValue);
}
(当然,我可以使用.map(...) 而不是.forEach(...) 返回Integer.toString(i),但这不是我要在此处说明的内容,而且出于效率原因或因为您必须让工人设置或返回许多不同的值。)
在实践中,当从一个线程设置数组条目然后从另一个线程读取时,我从未见过 strValues 数组条目等于 null。但是,我知道Java的内存模型并不能保证这一点,因此存在AtomicInteger等。
但在 Java 中没有 AtomicArray 等价物。最好的办法是用空的AtomicReference 对象初始化AtomicReference[] 数组,然后从工作线程中设置它们。但这在 CPU 资源和内存上效率非常低。
也没有办法可靠地刷新 CPU 的所有缓存,无论是从 Java 还是可能的 at all。
我知道栅栏的存在是为了防止内存操作重新排序,但我认为它们不会改变内存刷新语义。还是内存操作重新排序是导致 Java 内存模型需要 Atomic* 类的唯一问题?
我的主要问题:如何从一个线程(或一组工作线程)设置数组中的值,然后尝试从另一个线程读取它们,而不会遇到过时的值?特别是我很想知道当工作线程到达流的末尾时是否设置了适当的内存栅栏或类似的东西。 (我看不出这怎么能自动完成,所以我猜它不会发生。)
【问题讨论】:
标签: java concurrency memory-model java-memory-model