多线程并发下的指令重排问题
在多线程并发情况下,指令重排会出现问题,先看下面一个例子:
public class DemoCount {
public static int r1, r2, x, y;
public static void main(String[] args) throws InterruptedException {
boolean f1, f2, f3, f4;
f1 = f2 = f3 = f4 = false;
int count = 0;
while (true) {
r1 = r2 = x = y = 0;
Thread t1 = new Thread(() -> {
x = 1;
r1 = y;
});
Thread t2 = new Thread(() -> {
y = 1;
r2 = x;
});
t1.start();
t2.start();
t1.join();// 确保线程0、1能够执行完main线程打印后面的输出结果
t2.join();// 确保线程0、1能够执行完main线程打印后面的输出结果
++count;
if (r1 == 0 & r2 == 1 & !f1) {
System.out.println("第" + count + "次出现结果: r1=" + r1 + ":r2=" + r2);
f1 = true;
}
if (r1 == 1 & r2 == 0 & !f2) {
System.out.println("第" + count + "次出现结果: r1=" + r1 + ":r2=" + r2);
f2 = true;
}
if (r1 == 0 & r2 == 0 & !f3) {
System.out.println("第" + count + "次出现结果: r1=" + r1 + ":r2=" + r2);
f3 = true;
}
if (r1 == 1 & r2 == 1 & !f4) {
System.out.println("第" + count + "次出现结果: r1=" + r1 + ":r2=" + r2);
f4 = true;
}
}
}
}
运行会产生四种结果:
第1次出现结果: r1=0:r2=1
第59次出现结果: r1=1:r2=0
第359000次出现结果: r1=1:r2=1
第47518222次出现结果: r1=0:r2=0
这里说明下,出现 r1=0
、r2=0
的情况表示出现了指令重排序,我们可以查看代码,两条代码交换位置其实是不影响结果,所以可以发生重排序,针对单线程来看,这种重排序是没有问题,但是多线程并发情况下就会出现问题,所以r1=r2=0
就是因为多线程情况下发生了指令重排序。
从上面这个例子我们可以通俗易懂的理解什么叫做指令重排
。解决这个问题就可以使用原语 volatile
禁止指令重排序,底层通过四条内存屏障指令实现。