1.CAS全称
全称:compare and swap,比较并交换。
虽然翻译过来是[比较并交换],但它是一个原子性的操作,对应到CPU指令为cmpxchg。
2.通俗理解CAS
- CAS 有三个操作数:当前值A、内存值V、要修改的新值B。
- 假设 当前值A 跟 内存值V 相等,那就将内存值V 改成B。
- 假设 当前值A 跟 内存值V 不相等,要么就重试,要么就放弃更新。
- 将当前值与内存值进行对比,判断是否有被修改过,这就是CAS的核心。
3.CAS的问题
CAS有个缺点就是会带来ABA的问题。
从CAS更新的时候,我们可以发现它只比对当前值和内存值是否相等,这会带来个问题,下面我举例说明下:
- 假设线程A读到当前值是10,可能线程B把值修改为100,然后线程C又把值修改为10。
- 等到线程A拿到执行权时,因为当前值和内存值是一致的,线程A是可以修改的!
- 站在线程A的角度来说,这个值是从未被修改的 。
- 这是不合理的,因为我们从上帝的角度来看,这个变量已经被线程B和线程C修改过了。
4.解决ABA问题
要解决ABA的问题,Java也提供了AtomicStampedReference类供我们用,说白了就是加了个版本,比对的就是内存值+版本是否一致。
疑问:
为什么阿里巴巴开发手册提及到推荐使用 LongAdder 对象,比AtomicLong 性能更好(减少乐观锁的重试次数)?
原因:
因为AtomicLong做累加的时候实际上就是多个线程操作同一个目标资源。
在高并发时,只有一个线程是执行成功的,其他的线程都会失败,不断自旋(重试),自旋会成为瓶颈。
而LongAdder的思想就是把要操作的目标资源 分散,到数组Cell中。
每个线程对自己的 Cell 变量的 value 进行原子操作,大大降低了失败的次数。
这就是为什么在高并发场景下,推荐使用LongAdder 的原因。
对于LongAdder 的详解在这篇文章!!!--->为什么阿里推荐 LongAdder ,不推荐 AtomicLong ??