重排序

所谓重排序,是指编译器和Java虚拟机通过改变程序的处理顺序来优化程序。实际上,在运行单线程程序时无法判断是否进行了重排序。这是因为,虽然处理顺序改变了,但是规范上有很多限制可以避免程序出现运行错误。
但是,在多线程程序中,有时就会发生明显是由重排序导致的运行错误。

示例

在Java内存模型中,是有可能显示出x<y的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Main {

public static void main(String[] args) {
final Something obj = new Something();

new Thread() {
@Override
public void run() {
obj.write();
}
}.start();

new Thread() {
@Override
public void run() {
obj.read();
}
}.start();
}
}

class Something {
private int x = 0;
private int y = 0;

public void write() {
x = 100;
y = 50;
}

public void read() {
if (x < y) {
System.out.println("x < y");
}
}
}

原因就在于重排序。
在write方法中,由于对x的赋值和对y的赋值之间不存在任何依赖关系,编译器可能会改变赋值顺序。而且,在线程A已经为y赋值,但是尚未为x赋值之前,线程B也可能会去查询x和y的值并执行if语句进行判断。这时,x<y的关系成立。

kdPFxS.png

虽然代码是未正确同步的程序,但是如果将write和read都声明为synchronized方法,就可以实现正确同步的程序。