CAS之AtomicInteger原理解析

CAS是一种乐观锁机制,一种比较并交换的过程和理念,用来解决线程安全问题,具体来讲就是对共享变量值的安全更新机制。能够保证原子、可见、一致性。这种交换过程是在Unsafe类中实现。

从一段AtomicInteger类的方法调用代码开始来对源码做分析

    public static void main(String[] args) {
        AtomicInteger ai = new AtomicInteger(0);
        ai.getAndAdd(1);
        System.out.println(ai.get());

        //打印对象ai的内存结构,需要引入jol-core工具包
        ClassLayout classLayout = ClassLayout.parseInstance(ai);
        System.out.println(classLayout.toPrintable());
    }

从 new AtomicInteger(0) 进入先看静态代码块和构造方法,再看ai.getAndAdd(1)做了什么。

public class AtomicInteger extends Number implements java.io.Serializable {
    ...
    
    private static final long valueOffset;

    static {
        try {
            //获取初始值value的内存偏移量,这个偏移量指的是变量相对于对象地址的偏移,通过此偏    
            移可以获取变量在内存中的值,后面还会介绍
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    
    //初始化的时候给value赋值
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }

    //具体实现,需要进入到Unsafe类中
    public final int getAndAdd(int delta) {
        //this-当前atomicInter对象;valueoffest-内存偏移量;delta需要增加的值
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
}
   

 进入到Unsafe.getAndAddInt方法中

 public final class Unsafe {
    ...

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            //通过AtomicInteger对象和其变量value的偏移量获取内存中的value值,这里var5对其他线程                            
            是可见的, 如果不可见,那么这个值的获取就可能非内存真实值。
            var5 = this.getIntVolatile(var1, var2);
          //compareAndSwapInt的过程是原子性的,将重新获取到的内存value值与var5比较,true则说明
            value的内存值并未被修改,可以将原值var5 + 增值var4。
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }
}  

通过断点看具体的值

CAS之AtomicInteger原理解析_第1张图片

 再来看偏移量是什么,下面是AtomicInteger类型对象ai的内存结构

java.util.concurrent.atomic.AtomicInteger object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           bd 3d 00 f8 (10111101 00111101 00000000 11111000) (-134201923)
     12     4    int AtomicInteger.value                       1
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

请看标红的位置,由于对象的分配是在一个地址段内,对象中变量就是基于对象初始地址作了偏移,这里是对象中value变量相对对象初始地址的位置,其值最终为1。CAS之AtomicInteger原理解析_第2张图片

以上大概对CAS的解析,有人会问到CAS的弊端。如下

1 只能处理单个共享变量 要处理多变量共享,可以选择替代方案比如AtomicReference、ThreadLocal、加锁。
2 do while循环会导致cpu空转,占用cpu资源 解决方案ThreadLocal、AQS
3 aba问题

比如线程一将值0->1->0,线程二感知不到线程一对值做了改变。看似不是问题,但还是有问题,假设线程一 有bug,只是结果对了,一旦这个值在线程一中与其他变量关联,那么结果可能是隐蔽而致命的。

解决方案 AtomicStampedReference

个人理解,有不对之处,望请指正,谢谢。

你可能感兴趣的:(java,开发语言,jvm)