AtomicInteger原子类底层的一些原理

AtomicLong、AtomicBoolean、AtomicReference、LongAdder等

都是无锁化或者叫乐观锁,判断此时此刻是否是某个值,如果是则修改,不是则重新查询一个最新的值,再次执行判断。这个操作叫CAS,compare and set(swap jdk8及以后)

Atomic原子类底层核心的原理就是CAS,无锁化,乐观锁,每次尝试修改的时候,就对比一下,有没有人修改过这个值,没有人修改,自己就修改,如果有人修改过,就重新查出来最新的值,再次重复那个过程

源码:

(1)变量的offset,volatile value 使其值对其他线程可见

 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;

(2)Unsafe:核心类,负责执行CAS操作

public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

(3)API接口:Atomic原子类的各种使用方式

最底层使用c代码,发送cpu指令,确保CAS操作绝对原子(通过指令来锁掉某一小块内存,并且保证只有一个线程在同一时间可以对此块内存数据做CAS操作)。

CAS的问题

  1. ABA问题

    如果某个值一开始是A,后来变成了B,然后又变成了A,你本来期望的是值如果是第一个A才会设置新值,结果第二个A一比较也ok,也设置了新值,跟期望是不符合的。所以atomic包里有AtomicStampedReference类,就是会比较两个值的引用是否一致,如果一致,才会设置新值

  2. 无限循环(自旋)

    大家看源码就知道Atomic类设置值的时候会进入一个无限循环,只要不成功,就不停循环再次尝试,这个在高并发修改一个值的时候其实挺常见的,比如你用AtomicInteger在内存里搞一个原子变量,然后高并发下,多线程频繁修改,其实可能会导致这个compareAndSet()里要循环N次才设置成功,所以还是要考虑到的。JDK 1.8引入的LongAdder来解决,是一个重点,分段CAS思路

    LongAdder

    大量线程并发更新一个原子类的时候,天然的一个问题就是自旋,会导致并发性能还是有待提升,比synchronized当然好很多了

    分段迁移,某一个线程如果对一个Cell更新的时候,发现说出现了很难更新他的值,出现了多次自旋的一个问题,如果他CAS失败了,自动迁移段,他会去尝试更新别的Cell的值,这样的话就可以让一个线程不会盲目的等待一个cell的值

  3. 多原子变量问题

    AtomicXXX类,只能保证一个变量的原子性,但是如果多个变量呢?你可以用AtomicReference,这个是封装自定义对象的,多个变量可以放一个自定义对象里,然后他会检查这个对象的引用是不是一个。