【源码】JUC —— AtomicInteger 解读
前言
JUC 下提供了大量的 原子操作类,以保证我们可以便捷的操作对应类型且保证 并发环境 下的 原子性。本章节解读 AtomicInteger
版本
JDK11
Unsafe
底层的操作基本都由 Unsafe 类提供,比如 CAS操作
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetInt(Object o, long offset,
int expected,
int x);
使用 native
方法调用 CPU指令(譬如 cmpxchg ) 实现 CAS 操作。CAS(compare and swap 比较和交换),简单地描述就是:
在对操作数执行变更后,写入内存前先将原操作数和内存中当前操作数进行 compare
如果相同,则表明此次更新有效,然后将更新后的结果与当前内存中的原操作数进行 swap
即 compare and swap,而整个 CAS操作 基于一个 CPU指令 实现,因此保证了 原子性
比如在上述方法中各参数的意义
- Object o:更新对象
- long offset:对应更新字段的 偏移量(用于定位字段)
- int expected:预期的原操作数值
- int x:被更新成的目标值
AtomicInteger
AtomicInteger ,基于 int 型变量的 原子操作类
属性及构造
// Unsafe
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
// 字段偏移量
private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
// 默认为 0
private volatile int value;
public AtomicInteger(int initialValue) {
value = initialValue;
}
public AtomicInteger() {
}
public final int get() {
return value;
}
public final void set(int newValue) {
value = newValue;
}
接受一个 int 值作为初始 value,value 由 volatile
关键字修饰用于保证 并发环境 下的 可见性
原子操作
分析几个核心的 原子操作 方法
getAndSet
// 更新并返回更新前的值
public final int getAndSet(int newValue) {
return U.getAndSetInt(this, VALUE, newValue);
}
----------------------Unsafe---------------------
@HotSpotIntrinsicCandidate
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
// 自旋,直到 CAS 成功
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, newValue));
return v;
}
@HotSpotIntrinsicCandidate
public native int getIntVolatile(Object o, long offset);
@HotSpotIntrinsicCandidate
public final boolean weakCompareAndSetInt(Object o, long offset,
int expected,
int x) {
// CAS native 方法
return compareAndSetInt(o, offset, expected, x);
}
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetInt(Object o, long offset,
int expected,
int x);
更新 oldValue 为 newValue,并返回 oldValue,底层依赖一段 自旋 操作,即可以理解为:不停地 CAS 直到成功
compareAndSet
public final boolean compareAndSet(int expectedValue, int newValue) {
return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
}
AtomicInteger 同时也对外暴露了 CAS方法
getAndXXX
// 递增 1 并返回 oldValue
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
}
// 递减 1 并返回 oldValue
public final int getAndDecrement() {
return U.getAndAddInt(this, VALUE, -1);
}
// 递增 delta 并返回 oldValue
public final int getAndAdd(int delta) {
return U.getAndAddInt(this, VALUE, delta);
}
-----------------------Unsafe-------------------
// 自旋
@HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
依赖 自旋 + CAS,更新 oldValue 为 newValue,并返回 oldValue
XXXAndGet
public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
}
public final int decrementAndGet() {
return U.getAndAddInt(this, VALUE, -1) - 1;
}
public final int addAndGet(int delta) {
return U.getAndAddInt(this, VALUE, delta) + delta;
}
与 getAndXXX 类似,不同的是返回 newValue
Update
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev = get(), next = 0;
/**
* 自旋
* 修改 prev 为 next
* CAS 更新
* 更新失败且 oldPrev == newPrev,继续 CAS 更新
* 更新失败且 oldPrev != newPrev,修改 newPrev 为 next 再 CAS 更新
* 返回 prev
*/
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
// 返回 next
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
---------------IntUnaryOperator---------------
// 函数式接口,接受一个 int 参数,返回一个 int
@FunctionalInterface
public interface IntUnaryOperator {
int applyAsInt(int operand);
// 略
}
接受 自定义函数 更新 value,底层也是基于 自旋 + CAS
Accumulate
public final int getAndAccumulate(int x,
IntBinaryOperator accumulatorFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsInt(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return prev;
haveNext = (prev == (prev = get()));
}
}
public final int accumulateAndGet(int x,
IntBinaryOperator accumulatorFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = accumulatorFunction.applyAsInt(prev, x);
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}
-----------------IntBinaryOperator---------------
// 接受两个 int 参数,返回一个 int
@FunctionalInterface
public interface IntBinaryOperator {
int applyAsInt(int left, int right);
}
与 updateAndGet getAndUpdate 方法类似,只是该 函数接口 接受两个 int 参数,返回一个 int
类型转换
public int intValue() {
return get();
}
public long longValue() {
return (long)get();
}
public float floatValue() {
return (float)get();
}
public double doubleValue() {
return (double)get();
}
同时也提供了各种 类型转换 的方法
demo
public class AITest {
static AtomicInteger atomicInteger = new AtomicInteger(0);
static CountDownLatch countDownLatch = new CountDownLatch(100);
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
Thread t = new Thread(() -> {
atomicInteger.incrementAndGet();
countDownLatch.countDown();
});
t.start();
}
// 主线程 wait 等待子线程 CAS 完成后 countDown
countDownLatch.await();
// 保证了所有 CAS 完成后才输出
System.out.println(atomicInteger.get());
}
}
结果:
100
其他原子类
事实上,其他 原子类 比如 AtomicReference AtomicReferenceArray 等的原理基本也是如此,细节上不同的是其他类在 JAVA9 以后是基于 句柄变量VarHandle 进行 属性获取、CAS 等操作的
关于 句柄变量VarHandle,可自行了解
比如在 AtomicReference 中
// 句柄变量
private static final VarHandle VALUE;
// 基于 LookUp 赋值句柄变量
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private volatile V value;
--------------------CAS--------------------------
// 基于 VarHandle 的 CAS
public final boolean compareAndSet(V expectedValue, V newValue) {
return VALUE.compareAndSet(this, expectedValue, newValue);
}
其实在本质上,都是一样的
总结
原子操作类 在日常开发中也会经常用的,为我们提供了便捷安全的方法保证我们在 并发环境 下保证变量的 原子性,十分实用