我有关于 Java 中的 happens-before 机制的问题。这是示例:
public class MyThread extends Thread {
int a = 0;
volatile int b = 0;
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
read();
}
public void write(int a, int b) {
this.a = a;
this.b = b;
}
public void read() {
System.out.println(a + " " + b);
}
}
这是 happens-before 的明显例子,据我所知,这是足够安全的。 a
将正确地获得新值,因为它位于 b
的初始化之前。但重新排序是否意味着安全得不到保障?我在说这个:
public void write(int a, int b) {
this.b = b;
this.a = a;//might not work? isn't it?
}
UPD 主线程:
public class Main {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
t.write(1, 2);
}
}
最佳答案
使 b
volatile
并让 write
在将值设置为 之后将值设置为
保证:b
>a
- 如果
b
在a
之前被读取,那么 a
的值不会早于b
之前写入时的值。
也就是说,写入 b
和从 b
读取充当同步点或栅栏,这意味着写入 a
的任何内容code> 在写入 b
之前将在从 b
读取之后可读(如果 a
被写入多次,则以下写入可能或者可能不可见)。
但是,您的代码并不像现在这样安全。在 read
中,您有以下表达式:
a + " " + b
在 Java 中,expressions are evaluated left-to-right .这意味着,a
将在 b
之前被评估。因此,完全有可能读取 a
将看到 a
的旧值,而读取 b
将看到一个新值b
。如果您在 a
之前读取了 b
,则 b
的写入和读取之间的发生前关系将覆盖对 的写入a
和从 a
中读取。现在,它没有。
至于 write
中的重新排序操作 - 这将明显消除 b
的排序保证对 a
操作的影响,即使read
先读b
,再读a
。
为了可视化事物,仅给定 b
是 volatile
:
当前代码不保证 - 上的操作顺序
write a read a
write b --> happens before --> read b
使用给定的读取重新排序 write
也不会对 a
进行排序 -
read a
write b --> happens before --> read b
write a
即使给定的 read
是固定的,a
也不会按 b
排序 -
write b --> happens before --> read b
write a read a
唯一安全的做法是保持当前的write
,并修复read
-
write a
write b --> happens before --> read b
read a
关于java - Java中的happens-before机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25098539/