• 【面试:并发篇28:volatile】有序性


    【面试:并发篇28:volatile】有序性

    00.前言

    如果有任何问题请指出,感谢。

    01.介绍

    什么是有序性

    在不改变程序结果的前提下 指令可以在各个阶段通过重排序和组合来实现指令级并行。
    注意
    重排序指令不能影响结果

    为什么这样做

    cpu处理过程

    在cpu处理一个指令是包含一系列工序的,包含了:取指 译码 地址生成 执行 回写,这五步 但是这五步之间是可以交错运行的,也就是一个指令译码的时候另一个指令可以取指。
    例子1

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


    这样的执行效率显然更加的快,且在语句之间没有关系时 执行顺序可以随便,也就是可能先执行y=b 再执行x=a,不影响结果

    例子2

    	x=a;
    	c=x+1;
    	y=b;
    
    • 1
    • 2
    • 3

    这段代码是否可以套用上述的图片,是不行的。
    理论上应该对应的是下面这幅图

    但实际上这段代码被优化后可能是

    	x=a;
    	y=b;
    	c=x+1;
    
    • 1
    • 2
    • 3

    对应的图片

    这样做的原因是c=x+1需要x的值确定 也就是一定要等待x的指令全部完成之后才能执行c的指令,但是按照最初的顺序y=b是在最后的 也就是他也需要在x指令执行完才能运行 但是y=b和前两个指令没有任何关系,所以进行了优化 使得在x运行期间 y也可以运行,提高了并发性,使单独一个指令运行的情况减少。
    总结:例子二的这种情况就是指令重排序,在单线程情况下没有什么影响,但是在多线程情况下就有可能出问题。

    02.多线程情况下的指令排序

    public class Disorder {
        private static int x=0,y=0;
        private static int a=0,b=0;
        //无论这两个线程怎么排列组合 如果没有重排序,一定不会存在x=0 且 y=0
        public static void main(String[] args) throws InterruptedException {
            int i=0;
            //不停的死循环
            while (true){
                i++;
                x=0;y=0;
                a=0;b=0;
                Thread one= new Thread(()-> {
                    //前后没有依赖关系 a=1和 x=b
                    a=1;
                    x=b;
                });
                Thread other = new Thread(()-> {
                    //如果不存在乱序,b=1一定在y=a前面
                    b=1;
                    y=a;
                });
                one.start();other.start();
                one.join();other.join();
                String result = "第"+i+"次("+x+","+y+")";
                if(x==0 && y==0){
                    System.err.println(result);
                    break;
                }else{
                    System.out.println(result);
                }
            }
    
        }
        public static void shortWait(long interval){
            long start = System.nanoTime();
            long end;
            do{
                end=System.nanoTime();
            }while (start+interval>=end);
        }
    
    }
    
    • 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
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    结果

    .
    .
    .
    .
    第181799次(0,1)
    第181800次(0,1)
    第181801次(0,1)
    第181802次(0,1)
    第181803次(0,1)
    第181804次(0,0)

    解释
    我们分析上述代码,考虑到多线程的情况,理论上x,y最多组合的情况就只有3种(1,0) (1,1) (0,1),但是我们却发现了第四种情况(0,0) 要出现这种情况一定是x=b在a=1之前,y=a在b=1之前,很显然这种情况就只有指令重排序了

    03.禁止指令重排序

    很简单就是在x,y前加一个volatile,作用是保证在x,y之前的代码都比它先执行,例如a=1;x=b;保证a=1一定在x=b之前执行,同理y也是这样,同时把之前的变量包括自己的值同步到主存中。同时需要给a,b前加上volatile保证a b的可见性 要不然可能会出现a b已经更新到主存 但读取的还是本地内存
    补充:最后这段解释可能大家会理解的不清楚,具体解释涉及到volatile的原理,下一个文章会讲。

  • 相关阅读:
    2023湖北汽车工业学院计算机考研信息汇总
    POI-TL制作word
    Vue模板语法
    Responder
    【linux命令讲解大全】107.mkdir命令:创建目录的指令
    rust - 一个日志缓存记录的通用实现
    前馈神经网络解密:深入理解人工智能的基石
    深度学习-优化器
    淘宝API接口
    H.265 视频在浏览器中的播放问题探究
  • 原文地址:https://blog.csdn.net/m0_71229547/article/details/126024834