Java中的StoreStore内存屏障是否禁止读写重新排序?

现在我们有


Load A

StoreStore

Store B

是否有可能实际的执行顺序如下


StoreStore

Store B

Load A

如果可能的话,如何解释似乎违反的情况The Java volatile Happens-Before Guarantee。


据我所知,易失性语义是使用以下JMM内存屏障添加策略来实现的


insert a StoreStore before volatile variable write operation

insert a StoreLoad after volatile variable write operation

insert a LoadLoad after volatile variable read operation

insert a LoadStore after volatile variable read operation

现在如果我们有两个 java 线程,如下所示


线程1


Load A

StoreStore

Store volatile B

线程2


Load volatile B

Load C

根据《The Java volatile Happens-Beforeguarantee》,Load A应该happens-before Load Cwhen Load volatile Bis after Store volatile B,但是如果Load A可以重新排序到“after Store volatile B”,如何保证Load A is before Load C?


largeQ
浏览 68回答 2
2回答

慕勒3428872

从技术上讲,Java 语言不存在内存障碍。相反,Java 内存模型是根据发生在关系之前指定的;详细信息请参见以下内容:Java 中内存屏障的行为正如该文档所说,它是为编写实现 Java 内存模型的编译器的人们提供的指南。它正在解释JMM 的含义,显然无意成为官方规范。JLS 是规范。JSR-133 Cookbook 中有关内存屏障的部分根据它们限制特定加载和存储序列的方式对它们进行分类。对于StoreStore障碍,它说:该顺序:Store1; StoreStore; Store2 确保 Store1 的数据在与 Store2 关联的数据和所有后续存储指令之前对其他处理器可见(即刷新到内存)。一般来说,StoreStore处理器上需要屏障,否则不能保证从写入缓冲区和/或高速缓存到其他处理器或主存储器的刷新的严格顺序。正如您所看到的,StoreStore障碍仅限制操作的行为store。在您的示例中,您有一个load后跟一个store。屏障的语义StoreStore没有提及load操作。因此,您建议的重新排序是允许的。

有只小跳蛙

这只是回答您问题的更新部分。首先,您提供的示例不是 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 = 2b = 2发生在之前b == 2b == 2发生在之前print(a)除非涉及其他代码,否则发生之前链意味着线程“二”将打印“1”。笔记:编译代码时无需考虑编译器使用的内存屏障。这些障碍是特定于实现的并且是编译器内部的。如果您查看本机代码,您将不会看到内存屏障本身。您将看到具有所需语义的本机指令,以确保(隐藏的)内存屏障存在。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java