V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
esolve
V2EX  ›  问与答

如何理解 AtomicInteger 里的 CAS 操作?

  •  
  •   esolve · Apr 2, 2017 · 1902 views
    This topic created in 3322 days ago, the information mentioned may be changed or developed.
    为何要循环直到成功?如果这期间有另外的线程更改了 value ,导致 compareAndSet ()返回 false ,那这就表面已经不是原子性了吧,还继续重复有啥意义?


    public final int getAndIncrement() {
    for (;;) {
    int current = get();
    int next = current + 1;
    if (compareAndSet(current, next))
    return current;
    }
    }

    为何要循环直到成功?如果这期间有另外的线程更改了 value ,导致 compareAndSet ()返回 false ,那这就表面已经不是原子性了吧,还继续重复有啥意义?
    6 replies    2017-04-02 23:42:46 +08:00
    kaneg
        1
    kaneg  
       Apr 2, 2017 via iPhone
    因为 cas 是原子的,所以返回 true 就证明原子操作成功,该循环退出。若 cas 操作失败,说明被其他线程抢先,则继续循环,直到 cas 成功。

    用一句话总结就是:宏观的原子性操作是由无数的 cas 原子操作失败换来的唯一一次成功。
    honeycomb
        2
    honeycomb  
       Apr 2, 2017 via Android
    因为它的目的是要自增 1 ,且不需要保证调用它的线程的顺序:

    一群线程在竞争这个原子变量时,对于线程 A ,它的一次操作对应于 current 为 1 时自增到 2 是可以的,如果被另一个线程抢先的话, A 等下一个循环,从 2 自增到 3 也是可以的。

    从计数的角度来如此更换一下顺序不影响结果。

    如果竞争非常激烈,这样的乐观锁的性能不一定会比悲观锁性能好。
    esolve
        3
    esolve  
    OP
       Apr 2, 2017
    @kaneg 被其他线程抢先了,那还干嘛继续循环?
    譬如我现在 AtomicInteger 的值是 4,我期望其自赠变成 5
    但是被其他线程抢先了
    那我就应该放弃这次自赠啊
    如果想继续,那就再调用一下 getAndIncrement 啊
    esolve
        4
    esolve  
    OP
       Apr 2, 2017
    dingdingding
    slixurd
        5
    slixurd  
       Apr 2, 2017   ❤️ 1
    @esolve 因为你理解的作用不对....
    原始值是 4,他能保证执行了 2 次 getAndIncrement 结果一定是 6 的...
    wwqgtxx
        6
    wwqgtxx  
       Apr 2, 2017 via iPhone
    你要执行的是把一个变量+1 这个操作,而不是保证一定是访问的瞬间值+1 这个操作,所以如果同时有 n 个线程调用 getAndIncrement ,最后的结果应该是原始值+n 而不是原始值+1
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   1098 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 18:03 · PVG 02:03 · LAX 11:03 · JFK 14:03
    ♥ Do have faith in what you're doing.