Java AtomicInteger 原理
AtomicInteger是一个支持原子操作的int封装类,提供了原子性的访问和更新操作
其底层是通过volatile和CAS实现的,其中volatile保证了内存可见性,CAS算法保证了原子性
volatile
volatile是用于保证可见性的关键字,当变量被声明为volatile后,每次操作该变量都会强制将修改的值立即写入主存(volatile还能够保证一定的有序性,但这里不做介绍)
在AtomicInteger内部可以看到以volatile修饰的value字段用来记录数值,以保证可见性
private volatile int value;
CAS
CAS(Compare And Swap)即比较并交换,表示的是一系列操作的集合,获取当前数值进行一些运算,利用CAS指令试图进行更新。如果当前数值未变,代表没有其他线程进行并发修改,则成功更新。否则可能出现不同的选择,要么进行重试,要么就返回一个成功或者失败的结果
CAS底层依赖于CPU特定的指令集:
- x86上使用cmpxchg指令
- 精简指令集构架CPU通常依靠一对指令,如"load and reserve"和"store conditional"
源码解析
从AtomicInteger的内部属性可以看出,它依赖于Unsafe提供的一些方法来实现CAS操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
创建对象时,通过unsafe.objectFieldOffset
方法获取到内部变量value的内存偏移地址
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
Unsafe类可以实现一些不安全的操作,通常这些操作涉及到指针,如分配释放内存、定位属性在内存中的位置、挂起恢复线程、CAS操作等,由于使用风险较大因此Java9中限制了Unsafe类的使用并移除了一些功能
然后我们首先看下compareAndSet方法,该方法作用是将当前值与预期值进行比较,相等的话设置为更新值,更新成功返回true,失败返回false
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
可以看到内部调用了Unsafe中提供的compareAndSwapInt这个native方法,该方法会通过当前值的内存地址(offset)获得当前值的实际值与期望值(expected)进行对比,相同的话就替换为更新值(x),该方法基于CPU的特定的指令实现
public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);
接着看下原子更新方法,比如getAndIncrement方法,该方法作用是将当前值加一并返回加一前的值,类似i++
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
内部调用了Unsafe的getAndAddInt方法,该方法内循环的作用是CAS操作失败的重试逻辑
在多线程并发时,CAS操作不一定能够成功,因此通过不停的调用compareAndSwapInt直到返回true时退出循环,来实现非阻塞的原子性操作
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
其他原子更新方法原理相同,比如incrementAndGet,与getAndIncrement相比就是i++与++i的区别
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
参考
Java核心技术面试精讲
https://zhuanlan.zhihu.com/p/87141904
https://www.jianshu.com/p/51189b4ef6c1
https://juejin.im/post/5cc00f77f265da0359487485
https://fangjian0423.github.io/2016/03/16/java-AtomicInteger-analysis/