为什么使用两个 volatile 变量进行重新排序?
Why reordering takes place with two volatile variables?
我正在尝试调查 java 环境中的重新排序行为(使用 JDK 9-ea+170),发现一件事我自己无法解释,所以我会很高兴听到一些关于它的注释。这是一个例子:
public class Client {
int x;
int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
这个程序有一个 test()
方法,它只增加 x 和 y 值。我正在创建新线程并调用此 test()
直到某些内部 java 优化不更改 x++; y++;
指令的顺序()。这样我证明重新排序确实发生了。程序大部分时间都会结束(这是预期的)。
现在我已经为 y 添加了 volatile 修饰符:
public class Client {
int x;
volatile int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
这个程序永远不会结束,因为 volatile 保证 volatile 之前的所有指令都将被刷新到内存中,所以 x++;
总是在 y++;
之前执行,并且不可能有 y > x。这在我的理解中也是意料之中的。但在那之后我也将 volatile 添加到 int x;
现在我可以再次看到重新排序所以程序大部分时间结束:
public class Client {
volatile int x;
volatile int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
为什么重新排序也发生在这里?
这不是重新排序的证据。事实上,正在发生的事情是 ++
在 volatile
上不是原子的结果。例如,在更新其中一个变量 (x
) 时,请考虑两个线程(A
和 B
)的以下交错操作:
thread A: load x -> temp
thread B: load x -> temp
thread A: temp = temp + 1
thread B: temp = temp + 1
thread A: save temp -> x
thread B: save temp -> x
如果您使用这种交错完成这些操作,您会发现您已经失去了对 x
的计数。这足以让 c.y <= c.x
偶尔失败。
("lost count" 行为也可能发生在 y
......这解释了为什么这个实验只是在某些时候失败。)
我正在尝试调查 java 环境中的重新排序行为(使用 JDK 9-ea+170),发现一件事我自己无法解释,所以我会很高兴听到一些关于它的注释。这是一个例子:
public class Client {
int x;
int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
这个程序有一个 test()
方法,它只增加 x 和 y 值。我正在创建新线程并调用此 test()
直到某些内部 java 优化不更改 x++; y++;
指令的顺序()。这样我证明重新排序确实发生了。程序大部分时间都会结束(这是预期的)。
现在我已经为 y 添加了 volatile 修饰符:
public class Client {
int x;
volatile int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
这个程序永远不会结束,因为 volatile 保证 volatile 之前的所有指令都将被刷新到内存中,所以 x++;
总是在 y++;
之前执行,并且不可能有 y > x。这在我的理解中也是意料之中的。但在那之后我也将 volatile 添加到 int x;
现在我可以再次看到重新排序所以程序大部分时间结束:
public class Client {
volatile int x;
volatile int y;
public void test() {
x++;
y++;
}
public static void main(String[] args) {
Client c = new Client();
while(c.y <= c.x) new Thread(() -> c.test()).start();
System.out.println(c.x + " " + c.y);
}
}
为什么重新排序也发生在这里?
这不是重新排序的证据。事实上,正在发生的事情是 ++
在 volatile
上不是原子的结果。例如,在更新其中一个变量 (x
) 时,请考虑两个线程(A
和 B
)的以下交错操作:
thread A: load x -> temp
thread B: load x -> temp
thread A: temp = temp + 1
thread B: temp = temp + 1
thread A: save temp -> x
thread B: save temp -> x
如果您使用这种交错完成这些操作,您会发现您已经失去了对 x
的计数。这足以让 c.y <= c.x
偶尔失败。
("lost count" 行为也可能发生在 y
......这解释了为什么这个实验只是在某些时候失败。)