高并发编程之原子类AtomicInteger—源码剖析

AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的数值,通过调用底层Unsafe的CAS等方法实现原子操作。

源码分析

一、主要属性

  • (1)unsafe:Unsafe类的实例
  • (2)value:使用int类型的value存储值,且使用volatile修饰,volatile主要是保证可见性,即一个线程修改对另一个线程立即可见
  • (2)valueOffset:用于保存字段value的偏移量,用于后面的CAS操作

二、构造方法

有两个构造方法,如下:

  • AtommicInteger默认的值是0
  • AtomicInteger我们可以创建指定初始值的实例

三、compareAndSet()方法

Unsafe中的compareAndSwapInt()方法:

  • var1:操作的对象
  • var2:对象中字段的偏移量
  • var4:旧的期望值
  • var5:要修改的值

可以看到,这是一个native方法,底层是使用C/C++写的,主要是调用CPU的CAS指令来实现,它能够保证只有当对应偏移量处的字段值是期望值时才更新,即类似下面这样的两步操作:

if(value== expect ) {
   value=newValue;
}

通过CPU的CAS指令可以保证这两步操作是原子的,也就不会出现多线程环境中可能比较的时候value值是a,而到真正赋值的时候value值可能已经变成b了的问题。

四、getAndIncrement()方法

Unsafe中的getAndAddInt()方法

getAndIncrement()方法底层是调用的Unsafe的getAndAddInt()方法,这个方法有三个参数:

  • var1:操作的对象
  • var2:对象中字段的偏移量
  • var4:增量(这里写死为1)

这里方法展现了CAS的运行机制:可以看到它是先获取当前的值,然后再调用compareAndSwapInt()尝试更新对应偏移量处的值,如果成功了就跳出循环,如果不成功就再重新尝试,直到成功为止,这就是(CAS+自旋)的乐观锁机制。

和这个方法类似的有incrementAndGet()decrementAndGet()getAndDecrement()getAndAdd(int)addAndGet(int)……这些方法的底层都是调用了Unsafe类的compareAndSwapInt()方法,这里参照理解即可。

五、getAndUpdate(IntUnaryOperator updateFunction)

getAndUpdate()方法的参数类型是一个函数式接口,我们可以使用lambda定义各种计算操作,比如像下边实例:

public class AtomicIntegerTest {

    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(100);
        
        //x=x+10
        atomicInteger.getAndUpdate(x -> x + 10);
        System.out.println(atomicInteger.get());
        
        //x=x-10
        atomicInteger.getAndUpdate(x -> x - 10);
        System.out.println(atomicInteger.get());
        
        //x=x*10
        atomicInteger.getAndUpdate(x -> x * 10);
        System.out.println(atomicInteger.get());
        
        //x=x/10
        atomicInteger.getAndUpdate(x -> x / 10);
        System.out.println(atomicInteger.get());
        
        //x=x%10
        atomicInteger.getAndUpdate(x -> x % 10);
        System.out.println(atomicInteger.get());
    }
}

方法显示获得当前value的值,然后通过自定义的lambda操作计算出要修改的值,之后还是通过调用了Unsafe类中的compareAndSwapInt()实现了原子操作。与他有一个类的的方法updateAndGet()实现手段基本一样,只是返回值不同而已。

总结

(1)AtomicInteger维护了一个volaitle修饰的int类型的变量value来存储实际的值,这是CAS和voaltile的金典结合,既保证了变量修改的原子性,同时有保证了可见性。

(2)AtomicInteger的核心方法都最终与Unsafe中的compareAndSwapInt()方法有关(CAS),这个方法保证了变量修改的原子性。

(3)AtomicInteger是CAS在Java中的典型实现,看上去很完美,但是它却没有解决CAS带来的一个大问题:ABA问题

至于ABA问题在Java中如何解决,请参考我的另一篇博客深入源码分析原子类AtomicStampedReference

留言区

还能输入500个字符