本文采用知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
访问 https://creativecommons.org/licenses/by-sa/4.0/ 查看该许可协议。
java.util.concurent 包下有一个 atomic,作用如其名,atomic 包下的类可以解决原子性问题。
1) Atomic
juc 提供了一些原子性的工具,可以实现对象的原子性,如 AtomicInteger、AtomicLong 可以实现原子的 Integer 和 Long。
1.1) 原理
原理是基于 Java 的下层 API:Unsafe 的 CAS(Compare and swap)保证原子性,和 volatile 保证线程可见性。
CAS(无锁优化、自旋、乐观锁) 就是一个自旋,不断的比较目标实例是否符合预期原值,符合才将目标值 swap 到目标实例。
CAS 存在 ABA 问题:我们想将 A swap 成 C,但是在 CAS 过程中,A 的值发生过改变但最后又变回了 A,compare 成功,CAS
,这就是 ABA 问题,一般情况下不影响业务逻辑,可以通过 versionNum 来解决 ABA 问题,JUC 也提供了 AtomicStampedReference 解决 ABA 问题。
2) LongAdder/DoubleAdder
在 JDK8 后,atomic 包中新增了两个类,LongAdder、DoubleAdder
,在线程高竞争情况下 Adder 的效率要更高,但是会带来更大的空间消耗,且没有提供 xxAndGet 这样的 API,所以算是不安全的 Read。
2.1) 原理
Adder 相关类继承了 Striped64,Striped64 内部维护了一个 Cell 数组,并发时会把每个线程所做的修改分散到一个个 Cell 中
,Cell 中通过 CAS 实现原子性。当需要取 value 时,会把 Cell 中数据整合在一起,从而在线程竞争激烈时提高效率。
3) Accumulator
XXAdder 只能实现递增,如果有其他的需求,可以使用 XXAccumulator 自定义函数来实现非递增操作