美文网首页AndroidAndroid开发经验谈
Android线程篇(八):原子操作和指令重排

Android线程篇(八):原子操作和指令重排

作者: 小五666 | 来源:发表于2018-03-31 19:25 被阅读273次

    本文部分概念参考大神“海 子”博客,感谢作者:
    http://www.cnblogs.com/dolphin0520/p/3920373.html

    1.原子性操作

    来个例子:
    张三账户有1000大洋,李四账户有2000大洋,张三要给李四转账100大洋,在这个过程中:
    if成功:
    1.张三账户:1000-100=900
    2.李四账户:2000+100=2100
    if失败:
    1.张三账户:1000
    2.李四账户:2000
    我们把这种要么同时成功,要么同时失败要么同时成功的操作叫做具有原子性的操作。

    2.指令重排

    天天听大神说:指令重排,指令重排到底是个什么鬼?
    举个例子:

    int i = 0;              
    boolean flag = false;
    i = 1;                //语句1  
    flag = true;          //语句2
    

    上面代码定义了一个int型变量,定义了一个boolean类型变量,然后分别对两个变量进行赋值操作。从代码顺序上看,语句1是在语句2前面的,那么JVM在真正执行这段代码的时候会保证语句1一定会在语句2前面执行吗?不一定,为什么呢?这里可能会发生指令重排序(Instruction Reorder)。

    下面解释一下什么是指令重排序,一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。

    比如上面的代码中,语句1和语句2谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。

    但是要注意,虽然处理器会对指令进行重排序,但是它会保证程序最终结果会和代码顺序执行结果相同,那么它靠什么保证的呢?再看下面一个例子:

    int a = 10;    //语句1
    int r = 2;    //语句2
    a = a + 3;    //语句3
    r = a*a;     //语句4
    

    这段代码有4个语句,那么可能的一个执行顺序是:


    image.png

    那么可不可能是这个执行顺序呢: 语句2 语句1 语句4 语句3

    不可能,因为处理器在进行重排序时是会考虑指令之间的数据依赖性,如果一个指令Instruction 2必须用到Instruction 1的结果,那么处理器会保证Instruction 1会在Instruction 2之前执行。

    虽然重排序不会影响单个线程内程序执行的结果,但是多线程呢?下面看一个例子:

    //线程1:
    context = loadContext();   //语句1
    inited = true;             //语句2
     
    //线程2:
    while(!inited ){
      sleep()
    }
    doSomethingwithconfig(context);
    

    上面代码中,由于语句1和语句2没有数据依赖性,因此可能会被重排序。假如发生了重排序,在线程1执行过程中先执行语句2,而此是线程2会以为初始化工作已经完成,那么就会跳出while循环,去执行doSomethingwithconfig(context)方法,而此时context并没有被初始化,就会导致程序出错。

    从上面可以看出,指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。

    为什么要单独讲解原子性呢?原子性在多线程编程中要注意什么问题?如何解决指令重排在多线程下的影响呢?请关注下篇文章。

    相关文章

      网友评论

        本文标题:Android线程篇(八):原子操作和指令重排

        本文链接:https://www.haomeiwen.com/subject/cswhcftx.html