Java:能不能实现一个由指令重排引起的多线程不安全例子?

听说当两条指令互相不依赖的时候,在cpu或者jvm那儿可能会为了提高性能而进行指令重排。

 

 


数据依赖

比如下面两条代码就没有数据依赖:

int  a = 5;

int  b= 2;

这两条指令先后顺序并不影响程序运行逻辑,理论来说重排是没有问题的。


例子

但是,在多线程的时候就会出现问题,单个线程有依赖可以检测出来,

多个线程操作同一个对象的时候,因为每个线程都有自己的工作区,主存与工作内存交互不及时,就会导致数据出问题。

代码:

代码分析:

/**
     * 理论上来说:
     * 1.线程1先执行完,线程2开始执行
     *          a=1;
     *          flag=true;
     *          if (flag) {
     *                     a = a + 5;
     *                     System.out.println("reValue:" + a);
     *                 }
     *  运行结果是:输出reValue:6
     *
     *  2.线程1先执行一半,线程2执行
     *          a=1;
     *          if (flag) {
     *             a = a + 5;
     *             System.out.println("reValue:" + a);
     *          }
     *          flag=true;
     *  运行结果:无。
     *
     * 3.线程2先执行,线程1开始执行
     *          if (flag) {
     *                     a = a + 5;
     *                     System.out.println("reValue:" + a);
     *                 }
     *          a=1;
     *          flag=true;
     *  运行结果是:无。
     *
     * 如果在线程1中发生指令重排!!!!!
     * 就会出现:
     * 线程1先执行一半,线程2执行
     *          flag=true;
     *          if (flag) {
     *             a = a + 5;
     *             System.out.println("reValue:" + a);
     *          }
     *          a=1;
     * 运行结果:控制台输出reValue:a
     */
点击查看

运行结果:

我i5第十二代处理器,运行了一晚上,只出了这一次指令重排。它真的,我哭死。

还好运行出来一次,我勉强信了。


原因

它如何产生:就是因为每个线程都有自己的工作内存,而工作内存与主内存交互不够及时。

 


解决方案:

当你觉得某个变量会因为指令重排而导致线程不安全,那么对其使用volatile的声明,它使得变量及时地在主存中更新 :

1、对volatile变量的写会立即刷新到主存
2、对volatile变量的读会读主存中的新值

posted @ 2022-11-13 23:28  在博客做笔记的路人甲  阅读(163)  评论(0编辑  收藏  举报