在 JMM 的 happens-before 关系中重新排序

Reordering in happens-before relationship of JMM

关于 JMM 的 happens-before 关系(第 17.4.5 节)写在 JLS 中:

It should be noted that the presence of a happens-before relationship between two actions does not necessarily imply that they have to take place in that order in an implementation.

我对这种说法的例子很感兴趣。

我理解的对吗,举个例子:

Thread 1

x = 1
lock M
y = 2                            
unlock M ----------------------->Thread 2:

                                 lock M
                                 z = 3
                                 w = 4
                                 unlock M

显然,在此执行跟踪中,(x = 1) 和 (w = 4) 之间存在先行关系:

(x = 1) happens-before (w = 4)

同样在这种情况下,(x = 1) 在执行跟踪中与 (w = 4) 一起排序。

Thread 1 不使用变量 w。因此,我们可以将它放在 (x = 1) 之前而不违反 Thread 1Thread 2.

的逻辑

这是否意味着如果我们对 (x = 1) 和 (w = 4) 重新排序,那么这些语句之间的 happens-before 关系会保留?

如果您有其他示例,请提供。

是的,你是对的,happens-before关系在独立数据发生变化时成立。至于其他示例,请不要忘记 happens-before 也适用于同一线程中的事件。规则很简单:

If x and y are actions of the same thread and x comes before y in program order, then hb(x, y).

因此 Java 方法中的每个语句 happens-before 每个后续语句,当然 JIT-compiler 和 CPU 可以自由地重新排序独立语句(它们实际上是经常这样做以优化性能)。有时您可以从与当前线程没有 happens-before 关系的另一个线程观察到这种重新排序。

Thread 1 does not use variable w

你不能假设这是一个原因,因为实际上,Java 内存模型没有考虑在线程隔离上下文中重新排序指令是否安全,关于感知其他涉及线程
在没有锁定或内存屏障的情况下,JMM 仅保证 happens-before 个语句 在同一线程 中。

在你的例子中,你在同一个对象 (M) 上有一个锁定机制,所以 "happens-before" 发生了。
synchronized(锁定)或 Java 中的其他原子变量处理内存屏障 原子性。 有关信息,构造函数中的 volatile 变量和 final 变量赋值仅处理内存屏障。

以这个example为例,完全没有处理内存障碍:

Class Reordering {
  int x = 0, y = 0;
  public void writer() {
    x = 1;
    y = 2;
  }

  public void reader() {
    int r1 = y;
    int r2 = x;
  }
} 

Let's say that this code is executed in two threads concurrently, and the read of y sees the value 2. Because this write came after the write to x, the programmer might assume that the read of x must see the value 1. However, the writes may have been reordered. If this takes place, then the write to y could happen, the reads of both variables could follow, and then the write to x could take place. The result would be that r1 has the value 2, but r2 has the value 0.