在流的工作线程完成后确保内存一致性

Ensuring memory consistency after a stream's worker threads have completed

如何确保工作线程在以下代码中完成对流的处理后,即在(*)点,strValues数组的内容是一致的,即main (*) 处的线程在任何 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);
    }

(当然我可以 return Integer.toString(i) 使用 .map(...) 而不是 .forEach(...),但这不是我想在这里说明的,它是出于效率原因或因为您必须设置工人或 return 许多不同的值,并不总是可用的选项。)

实际上,当从一个线程设置数组条目然后从另一个线程读取数组条目时,我从未见过 strValues 数组条目相当于 null。但是,我知道 Java 的内存模型不能保证这一点,因此存在 AtomicInteger

但是 Java 中没有 AtomicArray 等价物。您可以做的最好的事情是用空 AtomicReference 对象初始化一个 AtomicReference[] 数组,然后从工作线程设置它们。但这在 CPU 资源和内存上效率很低。

也没有办法从 Java 或 at all.

可靠地刷新 CPU 的所有缓存

我知道栅栏的存在是为了防止内存操作重新排序,但我认为它们不会改变内存刷新语义。还是内存操作重新排序是导致 Java 内存模型需要 Atomic* 类 的唯一问题?

我的主要问题:如何从一个线程(或一组工作线程)设置数组中的值,然后尝试从另一个线程读取它们,而不 运行 进入陈旧值?我特别想知道当工作线程到达流的末尾时是否设置了适当的内存栅栏或类似的东西。 (我不知道如何自动完成,所以我猜它不会发生。)

But there is no AtomicArray equivalent in Java.

是的,有:AtomicReferenceArray<E>

int N = 50;
AtomicReferenceArray<String> strValues = new AtomicReferenceArray<>(N);
IntStream.range(0, N)
        .parallel()
        .forEach(i -> strValues.set(i, Integer.toString(i)));
for (int i = 0; i < strValues.length(); i++) {
    System.out.println(strValues.get(i));
}

此答案来源于Java volatile array?