![d5a0610a5ef4bcdf67c9d5b1b4a0e6fd.png](https://img-blog.csdnimg.cn/img_convert/d5a0610a5ef4bcdf67c9d5b1b4a0e6fd.png)
不知道大家有没有这样的感受:每当遇到一个新概念,特别是英文简称,觉得“高深莫测”,挺 NB 的亚子。
比如 JMM,CTL,ACK,JMS ,RPC,REST,CAS 和 ASQ 等。
![382de398b9a5481f3e78687ae1ea9264.png](https://img-blog.csdnimg.cn/img_convert/382de398b9a5481f3e78687ae1ea9264.png)
多次运行,我们发现使用 AtomicInteger ,最后输出的结果是 100000,和 synchronized 一样保证了原子性。
AtomicInteger 的底层,正是利用了【CAS机制】。
CAS (Compare And Swap的缩写)
比较并替换
CAS 机制当中使用了 3 个基本操作数:
内存值 V,旧的预期值 A,需要修改的新值 B。
![474aa9e6f39f3f8a4c2f40657a617c1e.png](https://img-blog.csdnimg.cn/img_convert/474aa9e6f39f3f8a4c2f40657a617c1e.png)
当 n 个线程同时对某个共享资源进行 CAS 操作,只有 1 个线程操作成功,不会和 synchronized 阻塞其他线程,其他线程只会收到操作失败的信号。CAS 是一个乐观锁。
AtomicInteger 的自增方法 incrementAndGet
![62f333d0943831fdc3ff456cc4df485e.png](https://img-blog.csdnimg.cn/img_convert/62f333d0943831fdc3ff456cc4df485e.png)
我们可以看到代码中使用了 do...while 循环,一个无限循环中,执行一个 CAS 操作,当操作成功,返回 true 时,循环结束;当返回 false 时,接着执行循环,继续尝试 CAS 操作,直到返回 true。
CAS的缺点:
① ABA 问题,如果内存中的数据从 A 变成 B,又变成 A ,CAS 操作无法识别数据的变化。使用带版本号的原子引用 AtomicStampedRefence,或者叫时间戳的原子引用,类似于乐观锁。
场景一:
假设你的话费余额是 100 元,有个游戏扣费业务(资费 50 元)由于故障发起了 2 次扣款,如果使用 CAS 操作,第一次成功扣款 50元,这时,你亲爱的老妈给你充了 50元,第二次扣款发现 内存值和旧的预期值相等,于是又扣了 50 元,话费余额又变成 50 元。
![cf07af4be03742033d702a4e77eaecf8.gif](https://img-blog.csdnimg.cn/img_convert/cf07af4be03742033d702a4e77eaecf8.gif)
场景二:比如单向链表 A->B,表头是 A,此时线程 t1 想把 表头换成 B,但是线程 t2 将链表改成 A->C->D,由
线程 t1 判断表头还是 A,会丢失 C 和 D.
![bf344bc7a9fb1f42c81777bfdefde698.png](https://img-blog.csdnimg.cn/img_convert/bf344bc7a9fb1f42c81777bfdefde698.png)
![8ce095ff36f190538aed0170dbbb7b57.png](https://img-blog.csdnimg.cn/img_convert/8ce095ff36f190538aed0170dbbb7b57.png)
② 不能保证代码块的原子性
CAS只是保证一个变量的原子性操作,如果涉及到代码块,可以使用 synchronized。
③ CPU 开销较大
高并发下,如果 n 个线程 CAS 操作一直处于 while 循环中,CPU开销很大,在并发量不是很高时cas机制会提高效率。
欢迎关注 @Python大星,一个会点 Python 的 Java 程序员。如文章描述有问题,评论下欢迎留言,有问题,你就说。
@Python大星 | 文