Java 记忆模型 - 令人惊讶的行为

Java Memory Model - Surprising Behaviors

我正在阅读 JSR-133 中的 Java 内存模型,但我不明白这种行为是如何被接受的:

有人可以解释一下吗?

8.1 Surprising Behaviors Allowed by the Memory Model

Figure 12 shows a small but interesting example. The behavior r1 == 2 and r2 == 1 is a legal behavior, although it may be difficult to see how it could occur. A compiler would not reorder the statements in each thread; this code must never result in r1 == 1 or r2 == 2. However, the behavior r1 == 2 and r2 == 1 might be allowed by a processor architecture that performs the writes early, but in a way that they were not visible to local reads that came before them in program order. This behavior, while surprising, is allowed by the Java memory model. To get this result in the memory model, we commit both writes followed by both reads.

不知何故 CPU 决定先写 x,然后再读 x。这个例子的全部意思是,这是或多或少的有效行为,这是一个被接受为有效行为的异常。

Intel Itanium CPU 可能会产生这种行为。

所以代替:

//Thread 1
int x = 0;
int r1 = x;
x = 1;

//Thread 2
int x = 0;
int r2 = x;
x = 2;

发生这种情况:

//Thread 1
int x = 0;
x = 2; //from Thread 2
int r1 = x;

//Thread 2
int x = 0;
x = 1; //from Thread 1
int r2 = x;

这是完全正确的。 (一个可接受的例外。)

CPU 必须确保的唯一一件事是在线程内对 X 的写入不会影响对其关联的 RX 内存位置的后续分配。它没有说明它从何处获取要写入的值。

所以, 在线程 1 中,CPU 表示
“哦,我需要读取 X”,因此开始读取操作。
然后说
“我需要写入 X”,因此 QUEUES 写入队列中的值

线程 2 做同样的事情。
“哦,我需要阅读 X”并开始阅读。
“我需要写入 X”,并将写入排队。

现在我们有两个等待读取和两个排队写入。

如果 CPU 体系结构表示一个内核上的读取可能会询问另一个内核的写入队列,那么两个内核都可以互相读取对 X 的未完成写入。因此,您会得到两个值被拉过内核,最终从该线程分配到 RX 内存位置。

当您在指令流中放置内存屏障时,它可以防止这种过度急切的排队写入读取。