AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
AutomicInteger是对int类型的一个封装,提供原子性的访问和更新操作,原子操作的实现是基于cas(compare-and-swap)来实现的。
什么是原子性访问?
一组操作要么全部成功,要么全部失败。
原子类操作都有哪些?
不光有AtomicInteger,还有很多原子类操作的类型。基本分为6类:
Atomic*:AtomicInteger、AtomicLong 和 AtomicBoolean
以AtomicInteger为例:
查看相关的方法:
把当前的值获取到,并且设置新的值。
获取当前的值,并且自增。为 +1
获取当前的值,并且自减。为 -1
获取当前的值,并加上预期的值,一次性地加减我们想要的数值。
如果输入的数值等于预期值,则以原子方式将该值更新为输入值(update)
Atomic*Array 数组
AtomicIntegerArray:整形数组原子类;
AtomicLongArray:长整形数组原子类;
AtomicReferenceArray :引用类型数组原子类。
AtomicIntegerArray:相当于将AtomicInteger组合成为一个数组。其他的类似,只是类型不同。
Atomic\Reference 引用类型原子类
AtomicReference ,让一个对象保证原子性。这样相比于AtomicInteger类型的好处就是,我们可以通过对象来同时对多个属性来赋值。
AtomicStampedReference:对 AtomicReference 的升级,在此基础上还加了时间戳,用于解决 CAS 的 ABA 问题。
AtomicMarkableReference:和 AtomicReference 类似,多了一个绑定的布尔值,可以用于表示该对象已删除等场景。
Atomic\FieldUpdater 原子更新器
- AtomicIntegerFieldUpdater:原子更新整形的更新器;
- AtomicLongFieldUpdater:原子更新长整形的更新器;
- AtomicReferenceFieldUpdater:原子更新引用的更新器。
将原来不具备原子性的变量,更新为原子的变量。
Adder 加法器
LongAdder 和 DoubleAdder
Accumulator 积累器
最后一种叫 Accumulator 积累器,分别是 LongAccumulator 和 DoubleAccumulator。
AtomicInteger 中的CAS
AtomicInteger 中getAndAdd
此处调用到Unsafe变量:
Unsafe 的 getAndAddInt 方法是通过循环 + CAS 的方式来实现的,在此过程中,它会通过 compareAndSwapInt 方法来尝试更新 value 的值,如果更新失败就重新获取,然后再次尝试更新,直到更新成功。
CAS更加底层如何实现的?
这依赖于CPU提供的特定指令,具体根据体系结构的不同还存在着明显区别。比如, x86 CPU提供cmpxchg指令;而在精简指令集的体系架构中,则通常是靠一对儿指令(如“load and reserve”和“store conditional”)实现的,在大多数处理器上CAS都是个非常轻量级的操作,这也是其优势所在。
如何在自己的产品代码中应用CAS操作?
Java9中移除了 Unsafe.moniter Enter()/moniterEXit(),导致无法平滑升级到新的JDK版本。目前Java提供了两种公共API,可以实现这种CAS操作,比如使用 java.util.concurrent.atomic.AtomicLongFieldUpdater,它是基于反射机制创建,我们需要保证类型和字段名称正确。