JAVA多线程高并发编程之 CAS

什么是CAS :

Compare and Swap,即比较再交换。在没有锁的情况下,能够保证多个线程对一个值的更新

CAS有3个操作数:内存值V、预期值A、要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。该操作是一个原子操作,被广泛的应用在Java的底层实现中。在Java中,CAS主要是由sun.misc.Unsafe这个类通过JNI调用CPU底层指令实现

执行流程如下:

有一个值 E=0, 对他进行加1 操作,一个线程读到E=0 后加1 ,计算后结果值v=1 ,
接下来比较E和E的当前最新值N(若有其他线程修改E记为N),如果相等就说明其他线程没有修改过E的值,更新E为最新的值V ,如果不相等,说明其他线程已经修改过E的值 比如说N=2,这时会重新读取E 的值,在计算结果值V=2+1,v=3后,在比较E和N 的值,相等更新不相等继续循环。


image.png

ABA问题

0 改为1 时回写时,其他线程把E的值从0改为2后又改为0,这样发现E的值还是0,其实已经发生过改变 。

乐观锁版本号
AtomicStampReference
读的时候不仅读取值还读取版本号。任何线程修改E的值的时候,都增加版本号,比较的时候,不仅比较值还比较版本号是否相同。

CAS源码实现如下:

AtomicInteger i = new AtomicInteger();
i.incrementAndGet();
    /**
     * Atomically increments by one the current value.
     *
     * @return the updated value
     */
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

可以看到是调用unfase 类的 getAndAddInt 方法,在往里面看

 do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

调用了一个方法compareAndSwapInt 这就是cas 操作的方法,在往里面看

    public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

调用了一个native 修饰的方法,native 修饰的是C/C++ 写的代码

hotspot 里面unsafe实现

image.png

调用了 Atimic::cmpxchg 方法
该方法的实现是 LOCK_IF_MP cmpxchg
LOCK_IF_MP: lock if Multi Processor 如果多个cpu
cmpxchg : compare and exchange 比较并交换

最终实现

lock cmpxchg 指令

lock 保证原子性是硬件级别的,cpu 在改变值的时候,其他的cpu不能对其进行修改

cpu 如何实现原子性

  • 总线锁:当一个线程操作共享变量时,在bus 总线上发出Lock信号,其他线程就不能操作这个变量了
  • 缓存锁:MESI 缓存一致性协议

CAS 优点

保证变量原子性

并发不高,时间不长的情况下,比锁效率高

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容