第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

时间:2024-04-13 08:17:53

AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

AutomicInteger是对int类型的一个封装,提供原子性的访问和更新操作,原子操作的实现是基于cas(compare-and-swap)来实现的。

什么是原子性访问?

一组操作要么全部成功,要么全部失败。

原子类操作都有哪些?

不光有AtomicInteger,还有很多原子类操作的类型。基本分为6类:
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

Atomic*:AtomicInteger、AtomicLong 和 AtomicBoolean

以AtomicInteger为例:

查看相关的方法:
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

把当前的值获取到,并且设置新的值。

第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
获取当前的值,并且自增。为 +1
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
获取当前的值,并且自减。为 -1

第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
获取当前的值,并加上预期的值,一次性地加减我们想要的数值。

第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?
如果输入的数值等于预期值,则以原子方式将该值更新为输入值(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
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

此处调用到Unsafe变量:

Unsafe 的 getAndAddInt 方法是通过循环 + CAS 的方式来实现的,在此过程中,它会通过 compareAndSwapInt 方法来尝试更新 value 的值,如果更新失败就重新获取,然后再次尝试更新,直到更新成功。
第22讲 | AtomicInteger底层实现原理是什么?如何在自己的产品代码中应用CAS操作?

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,它是基于反射机制创建,我们需要保证类型和字段名称正确。