个人随笔
目录
并发(三)、Java实现一段简单的会导致指令重排的例子
2021-04-20 17:11:54

我们知道,程序运行过程中,可能会发生CPU指令重排和编译器指令重排,那么程序开发过程中,会不会发生呢?
可能很多程序员在工作中基本上不会遇到,也就相当于没有直观性,那下面我们就来举个例子,代码如下:

  1. /**
  2. * 重排序测试
  3. * @author 爱吃鱼的乌贼
  4. *
  5. */
  6. public class ReorderTest {
  7. private static int a = 0;
  8. private static int b = 0;
  9. private static int x = 0;
  10. private static int y = 0;
  11. private static int i = 0;
  12. public static void main(String[] args) throws InterruptedException {
  13. for(;;) {
  14. i++;
  15. a=0;b=0;x=0;y=0;
  16. //创建2个CyclicBarrier对象,执行完后执行当前类的run方法
  17. CyclicBarrier cb = new CyclicBarrier(2);
  18. Thread t1 = new Thread(new Runnable() {
  19. public void run() {
  20. try {
  21. cb.await();
  22. } catch (Exception e) {
  23. // TODO Auto-generated catch block
  24. e.printStackTrace();
  25. }
  26. a=1;
  27. y=b;
  28. }
  29. });
  30. Thread t2 = new Thread(new Runnable() {
  31. public void run() {
  32. try {
  33. cb.await();
  34. } catch (Exception e) {
  35. // TODO Auto-generated catch block
  36. e.printStackTrace();
  37. }
  38. b=1;
  39. x=a;
  40. }
  41. });
  42. t1.start();
  43. t2.start();
  44. //t.join()方法只会使主线程(或者说调用t.join()的线程)
  45. //进入等待池并等待t线程执行完毕后才会被唤醒。并不影响同一时刻处在运行状态的其他线程。
  46. t1.join();
  47. t2.join();
  48. String result = "第"+i+"次执行结果x="+x+";y="+y;
  49. if(x==0&&y==0) {
  50. System.out.println("发生了指令重排");
  51. System.out.println(result);
  52. break;
  53. }else {
  54. System.out.println(result);
  55. }
  56. }
  57. }
  58. }

这边用CyclicBarrier来实现两个线程的同步执行。正常来说我们的程序x,y只会出现如下三种情况

  1. 1,1
  2. 1,0
  3. 0,1

除非发生指令重排,导致下面的逻辑

  1. a=1;
  2. y=b;
  1. b=1;
  2. x=a;

执行顺序变为

  1. y=b;
  2. a=1;
  1. x=a;
  2. b=1;

就有可能发生

  1. 0,0

那我们拭目以待吧,执行代码!

  1. 10765985次执行结果x=0;y=1
  2. 10765986次执行结果x=0;y=1
  3. 10765987次执行结果x=0;y=1
  4. 10765988次执行结果x=0;y=1
  5. 10765989次执行结果x=0;y=1
  6. 10765990次执行结果x=0;y=1
  7. 10765991次执行结果x=0;y=1
  8. 10765992次执行结果x=0;y=1
  9. 10765993次执行结果x=0;y=1
  10. 10765994次执行结果x=0;y=1
  11. 10765995次执行结果x=0;y=1
  12. 发生了指令重排
  13. 10765996次执行结果x=0;y=0

喵的,跑了一千万次才有一次重排,所以需要耐心,最起码证明了!

那要如何解决重排问题呢,只需要在a,b加上volatile关键字就可以了,volatile可以进制重排,保证有序性和可见性!

  1. private volatile static int a = 0;
  2. private volatile static int b = 0;
 387

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2