gpt4 book ai didi

Java在线程内对同一变量上的指令重新排序

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

在阅读了 JLS 并查看了多个场景之后,我不太清楚 Java 内存模型在线程内语义方面遵循哪些规则

将此代码仅用于示例目的:

public class CharIndexer {
public Map<char, int> charLastIndex;

public void changeCount(String phrase) {
Map<char, int> newCharLastIndex = new HashMap<char, int>();

for (int i = 0; i < s.length(); i++){
newCharLastIndex.put(s.charAt(i),i);
}

charLastIndex = newCharLastIndex;
}
}

在多个线程持有对同一 CharIndexer 实例的引用的场景中,读取字段 charLastIndex,同时其中一个线程调用 changeCount 方法。

如果对 charLastIndex 字段(方法上的最后一个赋值)的赋值是在 for block 之前完成的,那么这是否是有效的重新排序?

这将使读取线程能够看到尚未填充的 map 。

虽然我同意应使用 volatile 关键字明确可见性保证,但线程内语义是否允许此类重新排序?

两个订单的单线程执行会产生相同的结果,但哪些规则确实控制线程内重新排序,从而避免在此实现中对两个 for block 进行重新排序:

public class CharIndexer {
public Map<char, int> charLastIndex;

public void changeCount(String phrase) {
Map<char, int> newCharLastIndex = new HashMap<char, int>();

for (int i = 0; i < s.length(); i++){
newCharLastIndex.put(s.charAt(i),i);
}

// just changing values around
foreach(Map.Entry<char,int> charEntry : newCharLastIndex) {
charEntry.setValue(charEntry.getValue() * 10);
}

charLastIndex = newCharLastIndex;
}
}

我试图弄清楚 JIT 分析进行了多远,或者我是否不了解线程内语义的特定规则集。

最佳答案

如果没有生效的先行边界或同步块(synchronized block),操作的顺序(如另一个线程所见)可能是无序的。

最好的解释是,您的 HashMap 对象和 CharIndexer 对象可能位于计算机内存的不同部分。

在多 CPU 服务器上,内存访问由每个 CPU 独立缓存,因此当 CPU #1 运行 changeCount() 方法时,它的所有操作都在 CPU 1 缓存中完成。

最终,该缓存会刷新到主 RAM,一旦其他 CPU 从主 RAM 重新加载缓存,它们就可以看到它。

但是,保存HashMap的缓存部分和保存CharIndexer的缓存部分可能不会同时刷新+重新加载。因此,CPU #2 可能会在看到引用的 HashMap 的更新之前看到 CharIndexer 的更新。

这就是为什么您需要确保 HashMap 的构建发生在 charLastIndex 值的分配之前,或者两者都发生将发生在使用charLastIndex值之前。

关于Java在线程内对同一变量上的指令重新排序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36902104/

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