zoukankan      html  css  js  c++  java
  • 多线程并发的3个特性

    多线程并发开发中,要知道什么是多线程的原子性,可见性和有序性,以避免相关的问题产生。

    2.1 原子性
    原子性:即一个操作或者多个操作 要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行

    一个很经典的例子就是银行账户转账问题:

    比如从账户A向账户B转1000元,那么必然包括2个操作:从账户A减去1000元,往账户B加上1000元。

    试想一下,如果这2个操作不具备原子性,会造成什么样的后果。假如从账户A减去1000元之后,操作突然中止。这样就会导致账户A虽然减去了1000元,但是账户B没有收到这个转过来的1000元。

    所以这2个操作必须要具备原子性才能保证不出现一些意外的问题。

    2.2 可见性
    可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他线程能够立即看得到修改的值

    举个简单的例子,看下面这段代码:

    //线程1执行的代码
    int i = 0;
    i = 10;

    //线程2执行的代码
    j = i;
    当线程1执行int i = 0这句时,i的初始值0加载到内存中,然后再执行i = 10,那么在内存中i的值变为10了。

    如果当线程1执行到int i = 0这句时,此时线程2执行 j = i,它读取i的值并加载到内存中,注意此时内存当中i的值是0,那么就会使得j的值也为0,而不是10。

    这就是可见性问题,线程1对变量i修改了之后,线程2没有立即看到线程1修改的值。

    2.3 有序性
    有序性:程序执行的顺序按照代码的先后顺序执行

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

    什么是重排序?一般来说,处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证程序中各个语句的执行先后顺序同代码中的顺序一致。

    as-if-serial:无论如何重排序,程序最终执行结果和代码顺序执行的结果是一致的。Java编译器、运行时和处理器都会保证Java在单线程下遵循as-if-serial语意)

    上面的代码中,语句1和语句2谁先执行对最终的程序结果并没有影响,那么就有可能在执行过程中,语句2先执行而语句1后执行。但是要注意,虽然处理器会对指令进行重排序,但是它会保证程序最终结果会和代码顺序执行结果相同,那么它靠什么保证的呢?

    再看下面一个例子:

    int a = 10; //语句1
    int b = 2; //语句2
    a = a + 3; //语句3
    b = a*a; //语句4
    这段代码有4个语句,那么可能的一个执行顺序是: 语句2 语句1 语句3 语句4

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

    因为处理器在进行重排序时是会考虑指令之间的数据依赖性,如果一个指令Instruction 2必须用到Instruction 1的结果,那么处理器会保证Instruction 1会在Instruction 2之前执行。虽然重排序不会影响单个线程内程序执行的结果,但是多线程会有影响

    下面看一个例子:

    //线程1:
    init = false
    context = loadContext(); //语句1
    init = true; //语句2

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

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

    要想并发程序正确地执行,必须要保证原子性、可见性以及有序性。只要有一个没有被保证,就有可能会导致程序运行不正确。

  • 相关阅读:
    Hdu 5396 Expression (区间Dp)
    Lightoj 1174
    codeforces 570 D. Tree Requests (dfs)
    codeforces 570 E. Pig and Palindromes (DP)
    Hdu 5385 The path
    Hdu 5384 Danganronpa (AC自动机模板)
    Hdu 5372 Segment Game (树状数组)
    Hdu 5379 Mahjong tree (dfs + 组合数)
    Hdu 5371 Hotaru's problem (manacher+枚举)
    Face The Right Way---hdu3276(开关问题)
  • 原文地址:https://www.cnblogs.com/angdh/p/15569883.html
Copyright © 2011-2022 走看看