gpt4 book ai didi

java - Java 中的 volatile 数组和内存屏障以及可见性

转载 作者:行者123 更新时间:2023-11-30 06:52:12 25 4
gpt4 key购买 nike

我很难理解 Java 中的内存屏障和缓存一致性,以及这些概念与数组的关系。

我有以下场景,其中一个线程修改一个数组(对它的引用和它的一个内部值),另一个线程从中读取。

int[] integers;
volatile boolean memoryBarrier;

public void resizeAndAddLast(int value) {
integers = Arrays.copyOf(integers, integers.size + 1);
integers[integers.size - 1] = value;
memoryBarrier = true;
}

public int read(int index) {
boolean memoryBarrier = this.memoryBarrier;
return integers[index];
}

我的问题是,这是否按照我的想法进行,即“发布”到 memoryBarrier 并随后读取变量强制缓存一致性操作并确保读取线程确实会在指定索引处同时获取最新的数组引用和正确的基础值?

我的理解是数组引用不必声明为volatile,它应该足以使用any volatile 字段强制执行缓存一致性操作。这个推理正确吗?

编辑:正好有一个作者线程和许多读者线程。

最佳答案

不,您的代码是线程不安全的。使其安全的变体如下:

void raiseFlag() {
if (memoryBarrier == true)
throw new IllegalStateException("Flag already raised");
memoryBarrier = true;
}

public int read(int index) {
if (memoryBarrier == false)
throw IllegalStateException("Flag not raised yet");
return integers[index];
}

您只能升旗一次,并且不能发布超过一个 integers大批。不过,这对您的用例来说毫无用处。

现在,至于为什么...您不能保证在read() 的第一行和第二行之间没有对 integers 的干预写入这是由第二行观察到的。缺少内存屏障不会阻止另一个线程观察一个 Action 。它使结果不确定。

有一个简单的习惯用法可以使您的代码线程安全(专用于假设单个线程调用 resizeAndAddLast ,否则需要更多代码和 AtomicReference ):

volatile int[] integers;

public void resizeAndAddLast(int value) {
int[] copy = Arrays.copyOf(integers, integers.length + 1);
copy[copy.length - 1] = value;
integers = copy;
}

public int read(int index) {
return integers[index];
}

在此代码中,一旦数组发布,您就永远不会触及它,因此无论您从 read 中取消引用什么将按预期进行观察,并更新索引。

关于java - Java 中的 volatile 数组和内存屏障以及可见性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39408827/

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