2 回答
TA贡献1848条经验 获得超6个赞
从技术上讲,Java 语言不存在内存障碍。相反,Java 内存模型是根据发生在关系之前指定的;详细信息请参见以下内容:
Java 中内存屏障的行为
正如该文档所说,它是为编写实现 Java 内存模型的编译器的人们提供的指南。它正在解释JMM 的含义,显然无意成为官方规范。JLS 是规范。
JSR-133 Cookbook 中有关内存屏障的部分根据它们限制特定加载和存储序列的方式对它们进行分类。对于StoreStore
障碍,它说:
该顺序:
Store1; StoreStore; Store2
确保 Store1 的数据在与 Store2 关联的数据和所有后续存储指令之前对其他处理器可见(即刷新到内存)。一般来说,StoreStore
处理器上需要屏障,否则不能保证从写入缓冲区和/或高速缓存到其他处理器或主存储器的刷新的严格顺序。
正如您所看到的,StoreStore
障碍仅限制操作的行为store
。
在您的示例中,您有一个load
后跟一个store
。屏障的语义StoreStore
没有提及load
操作。因此,您建议的重新排序是允许的。
TA贡献1824条经验 获得超8个赞
这只是回答您问题的更新部分。
首先,您提供的示例不是 Java 代码。因此我们不能对其应用 JMM 推理。(只是为了让我们清楚这一点。)
如果您想了解 Java 代码的行为方式,请忘记内存屏障。Java 内存模型告诉您为了使内存读取和写入具有有保证的行为而需要执行的所有操作。以及推理(正确)行为所需了解的一切。所以:
编写您的 Java 代码
分析代码以确保在线程需要读取另一个线程写入的值的所有情况下,链之前都有正确的发生。
将(正确的)Java 代码编译为机器指令的问题留给编译器。
查看示例中的伪指令序列,它们没有多大意义。我不认为真正的 Java 编译器在编译真正的 Java 代码时会(在内部)使用这样的屏障。相反,我认为在每次易失性写入之后和每次易失性读取之前都会存在StoreLoad
内存屏障。
让我们考虑一些真实的 Java 代码片段:
public int a;
public volatile int b;
// thread "one"
{
a = 1;
b = 2;
}
// thread "two"
{
if (b == 2) {
print(a);
}
}
现在假设线程“二”中的代码在线程“一”之后执行,将会有一个发生之前链,如下所示:
a = 1
发生在之前b = 2
b = 2
发生在之前b == 2
b == 2
发生在之前print(a)
除非涉及其他代码,否则发生之前链意味着线程“二”将打印“1”。
笔记:
编译代码时无需考虑编译器使用的内存屏障。
这些障碍是特定于实现的并且是编译器内部的。
如果您查看本机代码,您将不会看到内存屏障本身。您将看到具有所需语义的本机指令,以确保(隐藏的)内存屏障存在。
添加回答
举报