AtomicInteger类源码剖析

AtomicInteger类源码剖析

一、AtomicInteger类的简介

AtomicInteger用于原子递增计数器等应用程序,不能用作Integer的替代品。然而,此类确实扩展了Number,以允许处理基于数字的类的工具和实用程序进行统一访问。

image-20231115112409671

二、AtomicInteger类的属性

AtomicInteger类主要利用CAS(compare and swap)+volatile和native方法来保证原子操作,从而避免synchronized的高开销,执行效率大为提升。

CAS的原理是拿期望的值和原本的一个值作比较,如果相同则更新成新的值。UnSafe类的objectFieldOffset()方法是一个本地方法,这个方法是用来拿到“原来的值”的内存地址。另外value是一个volatile变量,在内存中可见,因此JVM可以保证任何时刻任何线程总能拿到该变量的最新值。

1
2
3
4
5
6
// 底层原子更新都是依靠Unsafe对象的CAS操作
private static final jdk.internal.misc.Unsafe U = jdk.internal.misc.Unsafe.getUnsafe();
// 计算value字段的偏移量
private static final long VALUE = U.objectFieldOffset(AtomicInteger.class, "value");
// 原子整型类维护的值,volatile表明其内存可见性
private volatile int value;

三、AtomicInteger类的创建

1
2
3
4
5
6
7
8
9
10
public AtomicInteger(int initialValue) {
value = initialValue;
}

public AtomicInteger() {
}

public final void set(int newValue) {
value = newValue;
}

常见的使用场景无非是调用AtomicInteger的有参构造函数设置初始值,或者调用AtomicInteger的无参构造函数但随后立刻调用set方法设置初始值。

四、AtomicInteger类的重要方法

1.简单的常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 获取整型值
public final int get() {
return value;
}

// 原子更新为新值,返回旧值
public final int getAndSet(int newValue) {
return U.getAndSetInt(this, VALUE, newValue);
}

// 比较并更新,返回此次CAS操作结果
public final boolean compareAndSet(int expectedValue, int newValue) {
return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
}

// 原子递增,返回旧值
public final int getAndIncrement() {
return U.getAndAddInt(this, VALUE, 1);
}

// 原子递减,返回旧值
public final int getAndDecrement() {
return U.getAndAddInt(this, VALUE, -1);
}

// 原子增加delta,返回旧值
public final int getAndAdd(int delta) {
return U.getAndAddInt(this, VALUE, delta);
}

// 原子递增,返回新值
public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
}

// 原子递减,返回新值
public final int decrementAndGet() {
return U.getAndAddInt(this, VALUE, -1) - 1;
}

// 原子减少delta,返回新值
public final int addAndGet(int delta) {
return U.getAndAddInt(this, VALUE, delta) + delta;
}

2.复杂的常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// 使用应用给定函数的结果自动更新当前值,返回先前的值。该函数应该是无副作用的,因为当尝试更新由于线程之间的争用而失败时,它可能会被重新应用。
public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
// prev变化后需要重新计算next
if (!haveNext)
// 应用updateFunction根据prev计算next
next = updateFunction.applyAsInt(prev);
// CAS更新新值,更新成功立即返回旧值
if (weakCompareAndSetVolatile(prev, next))
return prev;
// 更新失败,检查prev是否保持不变
haveNext = (prev == (prev = get()));
}
}

// 与上一个类似,只不过返回新值
public final int updateAndGet(IntUnaryOperator updateFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
if (!haveNext)
next = updateFunction.applyAsInt(prev);
// CAS更新新值,更新成功立即返回新值
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}

// 使用将给定函数应用于当前和给定值的结果自动更新当前值,并返回先前的值。该函数应该是无副作用的,因为当尝试更新由于线程之间的争用而失败时,它可能会被重新应用。该函数应用当前值作为其第一个参数,给定的更新作为第二个参数。
public final int getAndAccumulate(int x,
IntBinaryOperator accumulatorFunction) {
int prev = get(), next = 0;
for (boolean haveNext = false;;) {
// prev变化后需要重新计算next
if (!haveNext)
// 应用accumulatorFunction根据prev和x计算next
next = accumulatorFunction.applyAsInt(prev, x);
// CAS更新新值,更新成功立即返回旧值
if (weakCompareAndSetVolatile(prev, next))
return prev;
// 更新失败,检查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);
// CAS更新新值,更新成功立即返回新值
if (weakCompareAndSetVolatile(prev, next))
return next;
haveNext = (prev == (prev = get()));
}
}

3.实现的父类方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public int intValue() {
return get();
}

public long longValue() {
return (long)get();
}

public float floatValue() {
return (float)get();
}

public double doubleValue() {
return (double)get();
}

4.依赖的底层方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Unsafe类的getAndSetInt方法:CAS+自旋重试
public final int getAndSetInt(Object o, long offset, int newValue) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, newValue));
return v;
}

// Unsafe类的getAndAddInt方法:CAS+自旋重试
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;
}

// Unsafe类的本地方法:CAS操作
public final native boolean compareAndSwapInt(Object o, long offset,
int expected,
int x);

总结,AtomicInteger类底层依赖的就是volatile的可见性+Unfase的CAS+失败自旋重试完成原子更新的!