gpt4 book ai didi

java - 流/fork-join 如何线程安全地访问数组?

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:22:56 25 4
gpt4 key购买 nike

Streams 和 fork-join 都提供了并行化访问数组的代码的功能。例如,Arrays.parallelSetAll 主要由以下行实现:

IntStream.range(0, array.length).parallel()
.forEach(i -> { array[i] = generator.applyAsLong(i); });

另外,documentation RecursiveAction 的一部分,fork-join 框架的一部分,包含以下示例:

static class SortTask extends RecursiveAction {
final long[] array; final int lo, hi;
...
void merge(int lo, int mid, int hi) {
long[] buf = Arrays.copyOfRange(array, lo, mid);
for (int i = 0, j = lo, k = mid; i < buf.length; j++)
array[j] = (k == hi || buf[i] < array[k]) ?
buf[i++] : array[k++];
}
}

最后,从数组创建的并行流在多个线程中访问数组(代码太复杂,无法在此总结)。

所有这些示例似乎都是在没有任何同步或其他内存障碍的情况下读取或写入数组(据我所知)。正如我们所知,完全即席的多线程数组访问是不安全的,因为不能保证读取反射(reflect)另一个线程中的写入,除非读取和写入之间存在先行发生关系。事实上,Atomic...Array 类就是专门为解决这个问题而创建的。但是,鉴于上面的每个示例都在标准库或其文档中,我认为它们是正确的。

谁能解释一下是什么机制保证了这些例子中数组访问的安全性?

最佳答案

简答:分区。

JMM 是根据对变量 的访问定义的。变量包括静态字段、实例字段和数组元素。如果你安排你的程序使得线程 T0 是唯一访问数组元素 0 的线程,类似地 T1 是唯一访问数组元素 1 的线程,那么这些元素中的每一个实际上都是线程限制的,并且你有没问题——JMM 程序顺序规则会为您服务。

并行流建立在这个原则之上。每个任务都在处理数组中没有其他任务处理的部分。那么我们所要做的就是确保运行任务的线程可以看到数组的初始状态,最终结果的消费者可以看到数组适当部分的任务修改 View .这些可以通过并行流和 FJ 库的实现中嵌入的同步操作轻松安排。

关于java - 流/fork-join 如何线程安全地访问数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37550386/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com