Atomic 整数类型
常用API
常见原子类:AtomicInteger、AtomicBoolean、AtomicLong
构造方法:
public AtomicInteger()
:初始化一个默认值为 0 的原子型 Integerpublic AtomicInteger(int initialValue)
:初始化一个指定值的原子型 Integer
常用API:
方法 | 作用 |
---|---|
public final int get() | 获取 AtomicInteger 的值 |
public final int getAndIncrement() | 以原子方式将当前值加 1,返回的是自增前的值 |
public final int incrementAndGet() | 以原子方式将当前值加 1,返回的是自增后的值 |
public final int getAndSet(int value) | 以原子方式设置为 newValue 的值,返回旧值 |
public final int addAndGet(int data) | 以原子方式将输入的数值与实例中的值相加并返回 实例:AtomicInteger 里的 value |
public final int getAndUpdate(IntUnaryOperator updateFunction) | 可以自定义操作逻辑 |
public final int updateAndGet(IntUnaryOperator updateFunction) | 可以自定义操作逻辑 |
原理分析
AtomicInteger 原理:自旋锁 + CAS 算法
CAS 算法:有 3 个操作数(内存值 V, 旧的预期值 A,要修改的值 B)
- 当旧的预期值 A == 内存值 V 此时可以修改,将 V 改为 B
- 当旧的预期值 A != 内存值 V 此时不能修改,并重新获取现在的最新值,重新获取的动作就是自旋
分析 getAndSet 方法:
AtomicInteger:
1
2
3
4
5
6
7public final int getAndSet(int newValue) {
/**
* this: 当前对象
* valueOffset: 内存偏移量,内存地址
*/
return unsafe.getAndSetInt(this, valueOffset, newValue);
}valueOffset:偏移量表示该变量值相对于当前对象地址的偏移,Unsafe 就是根据内存偏移地址获取数据
1
2
3
4valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
//调用本地方法 -->
public native long objectFieldOffset(Field var1);unsafe 类:
1
2
3
4
5
6
7
8
9
10// val1: AtomicInteger对象本身,var2: 该对象值得引用地址,var4: 需要变动的数
public final int getAndSetInt(Object var1, long var2, int var4) {
int var5;
do {
// var5: 用 var1 和 var2 找到的内存中的真实值
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var4));
return var5;
}var5:从主内存中拷贝到工作内存中的值(每次都要从主内存拿到最新的值到本地内存),然后执行
compareAndSwapInt()
再和主内存的值进行比较,假设方法返回 false,那么就一直执行 while 方法,直到期望的值和真实值一样,修改数据变量 value 用 volatile 修饰,保证了多线程之间的内存可见性,避免线程从工作缓存中获取失效的变量
1
private volatile int value
CAS 必须借助 volatile 才能读取到共享变量的最新值来实现比较并交换的效果
分析 getAndUpdate 方法:
getAndUpdate:
1
2
3
4
5
6
7
8public final int getAndUpdate(IntUnaryOperator updateFunction) {
int prev, next;
do {
prev = get(); //当前值,cas的期望值
next = updateFunction.applyAsInt(prev);//期望值更新到该值
} while (!compareAndSet(prev, next));//自旋
return prev;
}函数式接口:可以自定义操作逻辑
1
2AtomicInteger a = new AtomicInteger();
a.getAndUpdate(i -> i + 10);compareAndSet:
1
2
3
4
5
6
7
8
9public final boolean compareAndSet(int expect, int update) {
/**
* this: 当前对象
* valueOffset: 内存偏移量,内存地址
* expect: 期望的值
* update: 更新的值
*/
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}