在 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 1
和 Thread 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.
关于 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 1
和 Thread 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.