AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的数值,通过调用底层Unsafe的CAS等方法实现原子操作。
源码分析
一、主要属性
- (1)
unsafe
:Unsafe类的实例 - (2)
value
:使用int类型的value存储值,且使用volatile修饰,volatile主要是保证可见性,即一个线程修改对另一个线程立即可见 - (2)
valueOffset
:用于保存字段value的偏移量,用于后面的CAS操作
二、构造方法
有两个构造方法,如下:
- AtommicInteger默认的值是0
- AtomicInteger我们可以创建指定初始值的实例
三、compareAndSet()方法
Unsafe中的compareAndSwapInt()方法:
- var1:操作的对象
- var2:对象中字段的偏移量
- var4:旧的期望值
- var5:要修改的值
可以看到,这是一个native方法,底层是使用C/C++写的,主要是调用CPU的CAS指令来实现,它能够保证只有当对应偏移量处的字段值是期望值时才更新,即类似下面这样的两步操作:
if(value== expect ) {
value=newValue;
}
通过CPU的CAS指令可以保证这两步操作是原子的,也就不会出现多线程环境中可能比较的时候value值是a,而到真正赋值的时候value值可能已经变成b了的问题。
四、getAndIncrement()方法
Unsafe中的getAndAddInt()方法
getAndIncrement()方法底层是调用的Unsafe的getAndAddInt()方法,这个方法有三个参数:
- var1:操作的对象
- var2:对象中字段的偏移量
- var4:增量(这里写死为1)
这里方法展现了CAS的运行机制:可以看到它是先获取当前的值,然后再调用compareAndSwapInt()尝试更新对应偏移量处的值,如果成功了就跳出循环,如果不成功就再重新尝试,直到成功为止,这就是(CAS+自旋)的乐观锁机制。
和这个方法类似的有incrementAndGet()
、decrementAndGet()
、getAndDecrement()
、getAndAdd(int)
、addAndGet(int)
......这些方法的底层都是调用了Unsafe类的compareAndSwapInt()方法,这里参照理解即可。
五、getAndUpdate(IntUnaryOperator updateFunction)
getAndUpdate()方法的参数类型是一个函数式接口,我们可以使用lambda定义各种计算操作,比如像下边实例:
public class AtomicIntegerTest {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(100);
//x=x+10
atomicInteger.getAndUpdate(x -> x + 10);
System.out.println(atomicInteger.get());
//x=x-10
atomicInteger.getAndUpdate(x -> x - 10);
System.out.println(atomicInteger.get());
//x=x*10
atomicInteger.getAndUpdate(x -> x * 10);
System.out.println(atomicInteger.get());
//x=x/10
atomicInteger.getAndUpdate(x -> x / 10);
System.out.println(atomicInteger.get());
//x=x%10
atomicInteger.getAndUpdate(x -> x % 10);
System.out.println(atomicInteger.get());
}
}
方法显示获得当前value的值,然后通过自定义的lambda操作计算出要修改的值,之后还是通过调用了Unsafe类中的compareAndSwapInt()实现了原子操作。与他有一个类的的方法updateAndGet()
实现手段基本一样,只是返回值不同而已。
总结
(1)AtomicInteger维护了一个volaitle修饰的int类型的变量value来存储实际的值,这是CAS和voaltile的金典结合,既保证了变量修改的原子性,同时有保证了可见性。
(2)AtomicInteger的核心方法都最终与Unsafe中的compareAndSwapInt()
方法有关(CAS),这个方法保证了变量修改的原子性。
(3)AtomicInteger是CAS在Java中的典型实现,看上去很完美,但是它却没有解决CAS带来的一个大问题:ABA问题
至于ABA问题在Java中如何解决,请参考我的另一篇博客深入源码分析原子类AtomicStampedReference