CAS机制

CAS是什么

CAS是Compare And Swap(比较与交换)的缩写,是一种无锁算法,可以在不适用锁(没有线程被阻塞)的情况下实现多线程之间的同步,乐观锁用到了CAS机制。

CAS的实现

CAS涉及三个操作值

  1. 读写的内存值V
  2. 旧的预期值A
  3. 要写入的新值B

JDK1.8中AtomicInteger的源码,初始化方式有两种,可以用默认构造函数和初始化一个值。

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;
    
	public AtomicInteger(int initialValue) {
        value = initialValue;
    }
    /**
     * Creates a new AtomicInteger with initial value {@code 0}.
     */
    public AtomicInteger() {
    }

	public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    ...
}

valueOffset是偏移量,通过这个值和Class类的地址在内存中找到value
getAndAdd方法调用的是unsafe中的方法,进入Unsafe类中,找到getAndAddInt方法,这个方法在CPU层面能保证是原子性的,它一直在循环读取进行读取和更新的操作。var5是读取当前值内存上的值,然后执行var5+var4(var4就是delta值),写回的时候在判断现在内存上的值还是不是var5了,如果是,更新成功,返回的是内存上的旧值。如果不是,继续进行读取-写入操作。

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

CAS缺点

  1. ABA问题
    • 如果一个值原来是A,期间变成了B,又变回了A,那么使用CAS进行检查时会发现它的值没有发生变化,更新成功。
    • 解决方法:使用版本号
  2. 循环时间长开销大
    在并发量很大的情况下效果反而不好,所有线程竞争激烈,一直在反复修改提交,占用CPU资源。
  3. 只能保证一个共享变量的原子操作

处理器实现原子操作

  1. 使用总线锁保证原子性
    开销大,总线锁会阻止其他处理器访问整个内存
  2. 总线锁开销比较大,使用缓存锁保证原子性

这是CPU层面的实现,相当于JMM的主内存和工作内存。从缓存行写回主内存后,其他处理器缓存行内的该共享变量失效。

你可能感兴趣的:(并发编程)