目录
一、AtomicInteger的基本用法
1、创建AtomicInteger
2、常用方法说明
2.1、自增方法
2.2、自减方法
2.3、原子性的更新值
2.4、其他方法
3、AtomicInteger内幕
3.1、compareAndSwapInt 源码分析
3.2、getAndAddInt 自旋方法
四、总结
一、AtomicInteger的基本用法
AtomicInteger与int的引用类型Integer继承Number类一样,AtomicInteger也是Number类的一个子类,除此之外,AtomicInteger还提供了很多原子性的操作方法。在AtomicInteger的内部有一个被volatile关键字修饰的成员变量value,实际上,AtomicInteger所提供的所有方法主要都是针对该变量value进行的操作。
1、创建AtomicInteger
AtomicInteger类提供了AtomicInteger() 和 AtomicInteger(int initialValue) 两个构造方法,有参数的可以指定一个初始值,无参的构造方法默认值为0,相当于 AtomicInteger( 0 )。
2、常用方法说明
2.1、自增方法
- int getAndIncrement():返回当前 int 类型的value值,然后对value进行自增运算,该操作方法能够确保对value的原子性增量操作。
- int incrementAndGet():直接返回自增后的结果,该操作方法能够确保对value的原子性增量操作。
public static void main(String[] args) {
AtomicInteger count = new AtomicInteger(2);
// 先返回旧值,然后自增
("返回值:" + ());
//返回当前值
("当前值:" + ());
//直接返回自增后的结果
("返回值:" + ());
("当前值:" + ());
}
2.2、自减方法
- int getAndDecrement():返回当前int类型的value值,然后对value进行自减运算,该操作方法能够确保对value的原子性减量操作。
- int decrementAndGet():直接返回自减后的结果,该操作方法能够确保对value的原子性减量操作。
public static void main(String[] args) {
AtomicInteger count = new AtomicInteger(2);
// 先返回旧值,然后自减
("返回值:" + ());
//返回当前值
("当前值:" + ());
//直接返回自减后的结果
("返回值:" + ());
("当前值:" + ());
}
2.3、原子性的更新值
- boolean compareAndSet(int expect, int update):原子性地更新AtomicInteger的值,其中expect代表当前的AtomicInteger数值,update则是需要设置的新值,该方法会返回一个boolean的结果:当expect和AtomicInteger的当前值不相等时,修改会失败,返回值为false;若修改成功则会返回true。
- int getAndAdd(int delta):原子性地更新AtomicInteger 的value值,更新后的value为value和delta之和,方法的返回值为value的前一个值,该方法实际上是基于自旋+CAS算法实现的(Compare And Swap)原子性操作。
- int addAndGet(int delta):该方法与getAndAdd(int delta)一样,也是原子性地更新AtomicInteger的value值,更新后的结果value为value和delta之和,但是该方法会立即返回更新后的value值。
2.4、其他方法
- void set(int newValue):为AtomicInteger的value设置一个新值,通过对前面内容的学习,我们知道在AtomicInteger中有一个被volatile关键字修饰的value成员属性,因此调用set方法为value设置新值后其他线程就会立即看见。
- void lazySet(int newValue):set方法修改被volatile关键字修饰的value值会被强制刷新到主内存中,从而立即被其他线程看到,这一切都应该归功于volatile关键字底层的内存屏障。内存屏障虽然足够轻量,但是毕竟还是会带来性能上的开销,比如,在单线程中对AtomicInteger的value进行修改时没有必要保留内存屏障,而value又是被volatile关键字修饰的,这似乎是无法调和的矛盾。幸好追求性能极致的JVM开发者们早就考虑到了这一点,lazySet方法的作用正在于此。
- int get():返回AtomicInteger的value当前值。
3、AtomicInteger内幕
看看 AtomicInteger 类的内部原理,以更加深入地了解 AtomicInteger 的内幕。
// setup to use for updates
private static final Unsafe unsafe = ();
private static final long valueOffset;
static {
try {
valueOffset =
(("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
上面是 AtomicInteger 类的代码片段,我们看到 类中 主要有 一个量静态变量 Unsafe unsaf 和 volatile 修饰 的 int value 变量。AtomicInteger 内部也只要是通过Unsafe 类操作 value 变量来完成原子操作的。
3.1、compareAndSwapInt 源码分析
我们看下在 AtomicInteger 类内部的 compareAndSet 方法内部调用的就是 Unsafe 类的 compareAndSwapInt 方法。
public final boolean compareAndSet(int expect, int update) {
return (this, valueOffset, expect, update);
}
在 《CAS 原理》 一章中介绍过 CAS 操作包含三个三个参数分别为:内存值V、旧的预期值A、要修改的新值B,当且仅当预期值A与内存值V相等时,将内存值V修改为B,否则什么都不需要做。compareAndSwapInt 方法是一个 native 方法,其提供了CAS(Compare AndSwap)算法的实现,AtomicInteger类中的原子性方法几乎都借助于该方法实现。
3.2、getAndAddInt 自旋方法
由于compareAndSwapInt方法的乐观锁特性,会存在对value修改失败的情况,但是有些时候对value的更新必须要成功,比如调用incrementAndGet、addAndGet等方法,本节就来分析一下addAndGet方法的实现。
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = (var1, var2); // 1
} while(!(var1, var2, var5, var5 + var4)); // 2
return var5;
}
- 在 getAndAddInt 方法中有一个知道型 do .. while 循环语句,首先在注释 1 处获取当前被 volatile 关键字修饰的 value 值。
- 在 注释 2 处执行 compareAndSwapInt 方法如果执行成功则返回,如果执行失败则再次执行下一轮的 compareAndSwapInt 方法,直到成功。
四、总结
AtomicInteger 提供了一个原子性的操作,其内部是通过调用 Unsafe 类提供的 native 方法通过 CAS 操作实现的。在某些方法中更是通过 自旋 + CAS 的方式实现的更新操作。