我们知道,程序运行过程中,可能会发生CPU指令重排和编译器指令重排,那么程序开发过程中,会不会发生呢?
可能很多程序员在工作中基本上不会遇到,也就相当于没有直观性,那下面我们就来举个例子,代码如下:
/*** 重排序测试* @author 爱吃鱼的乌贼**/public class ReorderTest {private static int a = 0;private static int b = 0;private static int x = 0;private static int y = 0;private static int i = 0;public static void main(String[] args) throws InterruptedException {for(;;) {i++;a=0;b=0;x=0;y=0;//创建2个CyclicBarrier对象,执行完后执行当前类的run方法CyclicBarrier cb = new CyclicBarrier(2);Thread t1 = new Thread(new Runnable() {public void run() {try {cb.await();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}a=1;y=b;}});Thread t2 = new Thread(new Runnable() {public void run() {try {cb.await();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}b=1;x=a;}});t1.start();t2.start();//t.join()方法只会使主线程(或者说调用t.join()的线程)//进入等待池并等待t线程执行完毕后才会被唤醒。并不影响同一时刻处在运行状态的其他线程。t1.join();t2.join();String result = "第"+i+"次执行结果x="+x+";y="+y;if(x==0&&y==0) {System.out.println("发生了指令重排");System.out.println(result);break;}else {System.out.println(result);}}}}
这边用CyclicBarrier来实现两个线程的同步执行。正常来说我们的程序x,y只会出现如下三种情况
1,11,00,1
除非发生指令重排,导致下面的逻辑
a=1;y=b;
b=1;x=a;
执行顺序变为
y=b;a=1;
x=a;b=1;
就有可能发生
0,0
那我们拭目以待吧,执行代码!
第10765985次执行结果x=0;y=1第10765986次执行结果x=0;y=1第10765987次执行结果x=0;y=1第10765988次执行结果x=0;y=1第10765989次执行结果x=0;y=1第10765990次执行结果x=0;y=1第10765991次执行结果x=0;y=1第10765992次执行结果x=0;y=1第10765993次执行结果x=0;y=1第10765994次执行结果x=0;y=1第10765995次执行结果x=0;y=1发生了指令重排第10765996次执行结果x=0;y=0
喵的,跑了一千万次才有一次重排,所以需要耐心,最起码证明了!
那要如何解决重排问题呢,只需要在a,b加上volatile关键字就可以了,volatile可以进制重排,保证有序性和可见性!
private volatile static int a = 0;private volatile static int b = 0;
