深入刨析CAS

2020-06-07  本文已影响0人  Yangsc_o

[toc]



摘要

本文从CAS的基本操作开始,逐步探究CAS的实现原理,本文涉及代码使用JDK1.8版本;

CAS是什么?

CAS是Compare And Swap (Compare And Exchange) 的简称,从因为的意思也很容易理解:比较并交换。

public class CasDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(0);
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                atomicInteger.incrementAndGet();
            }
        },"a").start();
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                atomicInteger.incrementAndGet();
            }
        },"b").start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info(atomicInteger.get());
    }
}

CAS是如何实现的?

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;
    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;
    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    private volatile int value;
    ...
}
 /**
 * Atomically increments by one the current value.
 *
 * @return the updated value
 */
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        // 取出Object中偏移地址为var2的值var5;
        var5 = this.getIntVolatile(var1, var2);
        // 比较var1中偏移量为var2的值是否和var5相等?相等则更新为var5 + var4;
    } while (!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

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


JNI

翻看源码(如下面两张图所示)可以看到,不同的平台有不同的实现方式;

// Adding a lock prefix to an instruction on MP machine
#define LOCK_IF_MP(mp) "cmp $0, " #mp "; je 1f; lock; 1: "
cmpxchg

在atomic.cpp中则是通过递归实现的;

因为根据IA64手册,X86_64架构下,不跨越cacheline的8byte读写是原子的,如果你有个指针,没有跨越cacheline,那么多线程对这个指针的复制和读取都是不需要加锁的,可以保证原子的读到这8byte;

在这里插入图片描述

CAS存在的问题?


你的鼓励也是我创作的动力

打赏地址

上一篇 下一篇

猜你喜欢

热点阅读