深入理解CAS
1、什么是CAS
CAS(Compare And Swap比较和交换),是非阻塞同步的实现原理,它是CPU硬件层面的一种指令,从CPU层面能保证“比较与交换”两个操作的原子性。CAS操作包括三个参数:内存值(内存地址值)V、预期值E、新值N,当CAS指令执行时,当且仅当预期值和内存值相同时,才更新内存值为新值,否则就不执行更新。
2、CAS的使用
CAS在java.util.concurrent.atomic类、Java AQS、CurrentHashMap等是实现上有非常广泛的应用
3、CAS缺陷:
- 自旋CAS长时间不成功,则会给CPU带来非常大的开销
- 只能保证一个共享变量原子操作
- ABA问题
(数据库 乐观锁方案,每次修改一次数据,版本就会累加;Java提供了相应的原子引用类AtomicStampedReference)
4、LongAdder、DoubleAdder
AtomicLong利用了底层的CAS操作来提供并发性。在并发量低的情况下,线程冲突的概率小,自旋的次数不会太多。但是在高并发场景下,可能会出现大量失败并不断自旋的情况。
这就是引入LongAdder的初衷——解决高并发场景下AtomicInteger,AtomicLong的自旋瓶颈问题。
LongAdder原理
AtomicLong中有个内部变量value保存着实际的long值,所有操作都是围绕该变量进行。也就是说高并发环境下,value变量其实是一个热点。LongAdder的基本思路就是分散热点,将value的值分散到一个数组中,不同线程会命中到数组的不同槽中,各个线程只对自己槽中的那个值进行CAS操作,这样热点就分散了,冲突的概率就很小很多。如果要获取真正的long值,只要将各个槽中的变量累加返回。
LongAdder的内部结构
LongAdder内部有一个base变量,一个Cell[]数组
base变量:非竞态条件下,直接累加到该变量上
Cell[]数组:竞态条件下,累加各个线程自己的槽cell[i]中
LongAdder的使用场景
纯累加且高并发场景下使用LongAdder,经常被用作高并发计数器,统计指标(qps,流量)
低竞争条件下反而AtomicLong性能更好