您的位置:首页 > 其它

AtomicInteger源码分析

2017-07-25 10:30 99 查看
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) {

4000
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进行更新操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: