我在Java中遇到过关于先发生机制的问题。这是一个例子:
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);
}
}
这是发生在之前的明显例子,这是足够安全的,据我所知。 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);
}
}
答案 0 :(得分:4)
将b
volatile
设置为write
并将值设置为b
后,a
保证:
b
之前阅读a
,则a
的值不会超过之前写入b
时的值。即,b
的写入和b
的读取充当同步点或栅栏,这意味着在写入{{1}之前写入a
的任何内容从b
读取后将可读取(如果b
被写入多次,则以下写入可能会或可能不会显示)。
但是,您的代码现在不安全。在a
中,您有以下表达式:
read
在Java中,expressions are evaluated left-to-right。这意味着a + " " + b
将在a
之前进行评估。因此,b
的阅读完全有可能会看到a
的旧值,而a
的阅读会看到b
的新值。如果您在b
之前阅读b
,则a
的写入和读取之间的发生前关系将覆盖对b
的写入和{{1}的读取}}。现在,它没有。
至于a
中的重新排序操作 - 这将明确消除a
排序保证对write
上的操作的影响,即使b
首次读取a
1}}然后阅读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