关于重新排序:尽管使用了 volatile,为什么这段代码会抛出 RuntimeException?
About reordering: Why this code throws RuntimeException despite using the volatile?
public class ReOrdering implements Runnable {
int one, two, three, four, five, six;
volatile int volaTile;
@Override
public void run() {
one = 1;
two = 2;
three = 3;
volaTile = 92;
int x = four;
int y = five;
int z = six;
}
}
The assignments of one
, two
and three
may be reordered, as long as
they all happen before the volatile
write. Similarly, the x
, y
, and z
statements may be reordered as the volatile
write happens before all
of them. The volatile
operation is often called a memory barrier. The
happens before guarantee ensures that read and write instructions of
volatile
variables cannot be reordered across a memory barrier.
The happens before guarantee has another effect: When a thread writes
to a volatile
variable, then all other variables - including
non-volatiles - changed by the thread before writing to the volatile
variable are also flushed to main memory. When a thread reads a
volatile
variable it also reads all other variables - including
non-volatile - that were flushed to main memory together with the
volatile
variable.
© Bruce Eckel "On Java 8"
我一定是误解了什么,因为这段代码不是这样工作的
public class Reordering {
private int x;
private volatile int y;
public void writer() {
x = 1;
y = 2;
}
public void reader() {
if (y == 2) {
if(x == 0) {
// X assignment is happens-before for
// volatile Y assignment
// so X can't be 0 when Y equals 2
throw new RuntimeException();
}
x = 0;
y = 0;
}
}
public static void main(String[] args) {
Reordering reordering = new Reordering();
Thread thread = new Thread(() -> {
while (true) {
reordering.writer();
}
});
thread.setDaemon(true);
thread.start();
while (true) {
reordering.reader();
}
}
}
我认为,问题可能发生在编写者刚刚设置 x=1
,而 reader 已经在 if 块中(在变量赋值之前):
reader writer state
----------------- ------ --------
stops before x=0 x=1, y=2
x=1 x=1, y=2
x=0 x=0, y=2
y=0 x=0, y=0
y=2 x=0, y=2
reader will throw
public class ReOrdering implements Runnable { int one, two, three, four, five, six; volatile int volaTile; @Override public void run() { one = 1; two = 2; three = 3; volaTile = 92; int x = four; int y = five; int z = six; } }
The assignments of
one
,two
andthree
may be reordered, as long as they all happen before thevolatile
write. Similarly, thex
,y
, andz
statements may be reordered as thevolatile
write happens before all of them. Thevolatile
operation is often called a memory barrier. The happens before guarantee ensures that read and write instructions ofvolatile
variables cannot be reordered across a memory barrier.The happens before guarantee has another effect: When a thread writes to a
volatile
variable, then all other variables - including non-volatiles - changed by the thread before writing to thevolatile
variable are also flushed to main memory. When a thread reads avolatile
variable it also reads all other variables - including non-volatile - that were flushed to main memory together with thevolatile
variable.
© Bruce Eckel "On Java 8"
我一定是误解了什么,因为这段代码不是这样工作的
public class Reordering {
private int x;
private volatile int y;
public void writer() {
x = 1;
y = 2;
}
public void reader() {
if (y == 2) {
if(x == 0) {
// X assignment is happens-before for
// volatile Y assignment
// so X can't be 0 when Y equals 2
throw new RuntimeException();
}
x = 0;
y = 0;
}
}
public static void main(String[] args) {
Reordering reordering = new Reordering();
Thread thread = new Thread(() -> {
while (true) {
reordering.writer();
}
});
thread.setDaemon(true);
thread.start();
while (true) {
reordering.reader();
}
}
}
我认为,问题可能发生在编写者刚刚设置 x=1
,而 reader 已经在 if 块中(在变量赋值之前):
reader writer state
----------------- ------ --------
stops before x=0 x=1, y=2
x=1 x=1, y=2
x=0 x=0, y=2
y=0 x=0, y=0
y=2 x=0, y=2
reader will throw