简介
AtomicInteger 主要操作 int 类型的数据,通过调用 Unsafe 类的 CAS 等方法实现原子操作
成员变量
- value ,保存程序设定的值,用 volatile 修饰,保证可见性
- valueOffset,value 变量对应的内存偏移地址
// 获取 Unsafe 实例
private static final Unsafe unsafe = Unsafe.getUnsafe();
// value 字段的偏移量,相对于 AtomicInteger 对应实例的首地址的偏移量
private static final long valueOffset;
static {
try {
// 获取 value 的偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// 保存对应的值,保持可见性
private volatile int value;
构造方法
- 设置 volatile 修饰的 value 的值
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
成员方法
getAndSet
将 value 设定为 newValue
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
// Unsafe 中的方法
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var4));
return var5;
}
compareAndSet
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// Unsafe 中的方法
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
通过比较 valueOffset 处的值是否与 expect 相等,若相等,将 valueOffset 偏移量处的值更新为 update,否则不处理;
更新成功返回 true,更新失败返回 false。
getAndIncrement,getAndDecrement
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
// Unsafe 中的方法
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;
}
public native int getIntVolatile(Object var1, long var2);
将 valueOffset 对应的值加 1/减 1,注意这里有个循环的过程,直到更新成功。
返回更新前的 value
incrementAndGet
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
返回更新后的 value
CAS 问题
- 过度消耗 CPU
自旋 CAS 如果长时间不成功,会给 CPU 带来非常大的执行开销
- ABA 问题
Java 提供了 AtomicStampedReference 工具类,通过为引用建立类似版本号(stamp)的方式,来保证 CAS 的正确性。