zoukankan      html  css  js  c++  java
  • 多线程中的原子性问题及CAS

    线程中的原子性:

    所谓原子性,就是一系列操作,要么全部执行,要么全部不执行,不会存在只执行一部分的情况,举个例子,对于i++这个操作,那么这个自增的操作完整步骤分三步,读i的值----改i的值---写回i的值;如果不对i进行加锁,在执行这三步的时候,比如说改i的值的的时候,线程被打断了,那么就会出现预期结果不一致的问题,比如说在这个i++的操作中,读这一步的操作读到了i的值为1,然后在改之前,线程中断,i的值被其他线程改成了0,那此时,线程恢复,对i自增,把值改成2,写回的i的值为2,这就不合理,因为i的值被改成0了,对0自增一次却变成了2。

    CAS操作

    上面提到的原子性问题,在多线程环境下影响很大,虽然给变量加上volatile可以解决共享变量的读问题-----即内存可见性问题。(加了volatile的变量每次读值都会直接从主存读值,而不从自己的线程本地读值),就是说读--改---写这个步骤中,volatile可以解决读的问题,但是改和写这两个步骤的原子性还是无法保证,步骤整体的原子性依旧无法保证,还是存在在写或者改的时候被打断的情况。

    所以为解决这个问题,就出现了CAS,CAS的全称是compare and swap,CAS操作的整个步骤就是,拿到自己读取的值和内存的值比较,如果这两个值相同就说明没被其他线程改过,进行更新操作。如果不同就什么都不做,继续从内存中读取值,比较值,直到更新成功为止。这样的一个循环的过程。有点类似与乐观锁,示意图如下

    ABA问题

    但是CAS操作也会面临一个问题,就是ABA问题,ABA问题:有一个变量值为0,A线程拿到的值为0,然后要把他修改成1,然后改的过程中,其他线程B拿到这个变量值0.然后改成了2,最后又改回了0,或者有一个C线程把他改成了0,,虽然值为一样都为0,但是这个0已经不是原来的0了,这就是ABA问题。

    举个形象的例子就是,你女朋友跟你分手了,然后跟别人在一起,最后又跟你复合了。然后你们俩最后还是和之前一样在一起。但是感情已经不是原来的感情了。总结ABA问题就是: == 其他线程修改数次的最后值和原值相同 ==

    那么一般如何解决ABA问题,一般可以读值的时候带一个版本号,更新之前比较版本号,版本号一致则说明是同一个值,更新完毕之后,版本号+1。也是和乐观锁很像

    CAS如何解决原子性问题

    那么cas是怎么保证一致性的,会不会出现这种情况,在线程进行值修改的那个过程中,在执行修改指令的前一条指令执行之前。执行权被剥夺,值被其他的线程变了?

    CAS 底层的汇编实现 lock cmpxchg 指令 这个指令在对一块区域的值进行修改的时候,其他的线程和cpu不许打断这个指令,cas的一致性就是基于这条命令。lock指令非常重要,后面的synchronized都是基于这个lock指令,确保在执行lock指令的时候,直接锁住总线,不允许任何线程打断这个指令

  • 相关阅读:
    UVA 10617 Again Palindrome
    UVA 10154 Weights and Measures
    UVA 10201 Adventures in Moving Part IV
    UVA 10313 Pay the Price
    UVA 10271 Chopsticks
    Restore DB後設置指引 for maximo
    每行SQL語句加go換行
    种服务器角色所拥有的权限
    Framework X support IPV6?
    模擬DeadLock
  • 原文地址:https://www.cnblogs.com/blackmlik/p/12863466.html
Copyright © 2011-2022 走看看