AtomicInteger源码分析

AtomicInteger 是一个支持原子操作的 Integer 类,就是保证对AtomicInteger类型变量的增加和减少操作是原子性的,不会出现多个线程下的数据不一致问题。

AtomicInteger底层使用了CAS乐观锁的思想。CAS一直不太懂,今天正好好好研究一下。

下面先分析下源码:

1,成员变量:

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value;    //使用volatile修饰,保证获取的都是最新值

2,构造函数:一个默认构造函数,一个带着value参数的构造函数

public AtomicInteger(int var1) {
    this.value = var1;
}

public AtomicInteger() {
}

3,方法

public final int get() {
    return this.value; //因为value是volatile,所以获取的值都是最新的.

}

public final void set(int var1) {
    this.value = var1;    //直接对value设值
}

public final int getAndSet(int var1) {
    return unsafe.getAndSetInt(this, valueOffset, var1);//调用unsafe类的方法
}

unsafe的getAndSetInt方法:

public final int getAndSetInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);  //这是一个native方法,返回旧值
    } while(!this.compareAndSwapInt(var1, var2, var5, var4));   //这是一个native方法,如果新值代替旧值失败,自旋尝试直到成功

    return var5;
}

加减方法

public final int getAndIncrement() {   //加1,返回旧值
    return unsafe.getAndAddInt(this, valueOffset, 1);
}

public final int getAndDecrement() {  //减1,返回旧值
    return unsafe.getAndAddInt(this, valueOffset, -1);
}

public final int getAndAdd(int var1) {  //加var1,返回旧值
    return unsafe.getAndAddInt(this, valueOffset, var1);
}

public final int incrementAndGet() {   //加1,返回新值
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

public final int decrementAndGet() {   //减1,返回新值
    return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}

public final int addAndGet(int var1) {   //加var1,返回新值
    return unsafe.getAndAddInt(this, valueOffset, var1) + var1;
}
这些函数都是调用的unsafe的getAndAddInt()方法,下面看下这个方法:

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;
}
和前面getAndSetInt不同的是新值的不同,这次是增加var4.都是使用的CAS算法来保证原子性.


public final int getAndUpdate(IntUnaryOperator var1) {//IntUnaryOperator是功能接口
    int var2;
    int var3;
    do {
        var2 = this.get();//获得现在最新值
        var3 = var1.applyAsInt(var2);//将var2转化为int型
    } while(!this.compareAndSet(var2, var3));//调用compareAndSet

    return var2;//返回更新之前的值
}

public final int updateAndGet(IntUnaryOperator var1) {
    int var2;
    int var3;
    do {
        var2 = this.get();
        var3 = var1.applyAsInt(var2);
    } while(!this.compareAndSet(var2, var3));

    return var3;//返回更新之后的值
}

public final int getAndAccumulate(int var1, IntBinaryOperator var2) {
    int var3;
    int var4;
    do {
        var3 = this.get();
        var4 = var2.applyAsInt(var3, var1);
    } while(!this.compareAndSet(var3, var4));

    return var3;
}

public final int accumulateAndGet(int var1, IntBinaryOperator var2) {
    int var3;
    int var4;
    do {
        var3 = this.get();
        var4 = var2.applyAsInt(var3, var1);
    } while(!this.compareAndSet(var3, var4));

    return var4;
}

IntUnaryOperator和IntBinaryOperator都是功能接口,使用者可以自己实现这两个接口,自己定义applyAsInt函数,来决定更新的值如何变化,不仅仅是加减运算.

两者不同的是,IntUnaryOperator的applyAsInt只有一个参数,就是旧值.而IntBinaryOperator的applyAsInt有两个参数,一个是旧值,一个是自己设定的值.

compareAndSet方法也是调用CAS

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

还有一点不明:valueOffset是什么?

下面看看这个:

static {
    try {
        valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception var1) {
        throw new Error(var1);
    }
}
当前值存放的内存地址可以通过valueOffset来确定。实际上是“value字段相对Java对象的起始地址的偏移量”.

原来是这样的:compareAndSwapInt通过当前对象和偏移量来找到value的当前值,再和之前获得的旧值比较,看是否相等,相等则更新,返回true,不相等返回false.

总结:这里面最重要的就是:

value值使用volatile修饰保证可见性,然后是使用CAS保证对AtomicInteger的修改是线程安全的.

CAS:比较CPU内存上的值是不是当前值current,如果是就换成新值update,如果不是,说明获取值之后到设置值之前,该值已经被别人先一步设置过了,此时如果自己再设置值的话,需要在别人修改后的值的基础上去操作,否则就会覆盖别人的修改,所以这个时候会直接返回false,再进行无限循环,重新获取当前值,然后再基于CAS进行更新操作。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值