CAS总结

一:概念

是一种乐观锁,可以实现无锁并发。因为没有使用synchronized,所以线程不会阻塞,效率更高。但是如果竞争激烈,重试必然发生,那么效率反而受影响。

二:原子类

Java中提供了一些原子类,底层就是使用CAS实现的,例如AtomicInteger、AtomicLong、AtomicReference、AtomicStampedReference等

例如AtomicInteger提供了一个修改值的方法

  atomicInteger.compareAndSet()

这个方法实际上是调用unsafecompareAndSwapInt方法来保证原子性

  public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

其中valueOffset代表当前值,expect是预期值,update是更改值
例如:我们使用compareAndSet(1,3),此时就会将expec的值1与现在当前对象实际的值valueOffset进行比较,
如果一致,将将当前值更改为update值3

三:ABA问题

以上原子类使用CAS确实可以达到原子性,但是此时有一个问题,就是主线程只能判断共享变量是否与最初的值相同,并不能判断是否被其他线程修改,例如此时另一个线程做了+1,-1的操作,值和原来一致。虽然这并不影响操作,但是如果希望只要别的线程进行了操作,CAS就失败,该怎么处理呢?

AtomicStampedReference,通过版本号来判断是否被修改过,在修改时还需要判断版本号。并且版本号加1

四:LongAddr

LongAdder 是一个 Java 中的线程安全的累加器类型,它比原生的 AtomicLong 在高并发下更高效,因为它把内部的值分为多个 Cell 来处理,并且也允许多个线程同时在不同的 Cell 上进行增加操作,从而避免了高并发环境下的竞争问题

关键域:
base:基础值,如果没有竞争,则用CAS累加这个域
cells: 累加单元数组,懒惰初始化
cellsBusy:创建或者扩容时,置为1,表示加锁

源码

longAdder.increment();调用了add()
public void add(long x) {
    Cell[] as; long b, v; int m; Cell a;
    if ((as = cells) != null || !casBase(b = base, b + x)) { 
     //cells是累加单元数组,此处判断是否为空,因为cells初始是nul,即此处判断是否有竞争
     //如果为空,就进入casBase()方法,对基础累加值进行累加,base就是基础值,此处是一个CAS操作。累加成功就不会进入下面的代码块
        boolean uncontended = true;
        if (as == null || (m = as.length - 1) < 0 ||   //如果cells不为空,代表以前发生过竞争											
            (a = as[getProbe() & m]) == null ||        //判断当前线程的cell是否创建,没有创建就进入longAccumulate创建
            !(uncontended = a.cas(v = a.value, v + x)))//如果已经创建,执行累加单元的CAS,如果成功,则返回,如果失败,执行下面
            longAccumulate(x, null, uncontended);     // a.cas()失败,执行longAccumulate()
    }
}

你可能感兴趣的:(java)