并发编程专题-基础-6、CAS
1. JUC 中的 CAS
1.1. 是什么
1.2. 底层原理
1.2.1. 保证可见性
1.2.2. 保证原子性
1.3. 汇编实现
1.4. synchronized 中的 CAS
1.4.1. Atomic::cmpxchg_ptr
轻量级锁加锁的时候,如果处于无锁状态,则会通过 CAS 操作将锁对象的 Mark Word 更新为指向 Lock Record 的指针,相关代码如下:
1 |
|
其中 CAS 操作是通过 Atomic::cmpxchg_ptr(lock, obj()->mark_addr(), mark)
这段代码实现的。它有 3 个参数:
- 第一个参数是 exchange_value(新值)
- 第二个参数是 dest(目标地址)
- 第三个参数是 compare_value(原值)
它的含义是:
- 如果目标地址的值是原值,即
dest==compare_value
,则将其更新为新值,并且返回compare_value(原值)
。 - 否则,不做更新,并且返回第一个入参,
exchange_value(新值)
。 - 因此,当返回结果是
compare_value(原值)
时,则说明更新成功
虽然函数最后返回的是第一个入参 exchange_value(新值)
,但是返回之前,汇编底层将第二个入参 dest
的值赋值给了第一个参数 exchange_value
,所以最终返回的这个实际原值就是 dest
指向的值
1 |
|
1.4.2. 返回值
1.4.2.1. 返回第一个参数
1、
https://gorden5566.com/post/1055.html#waline
2、
https://blog.csdn.net/aileitianshi/article/details/108844586
1.4.2.2. 返回第二个参数✅
1、
https://juejin.cn/post/7104638789456232478
2、
https://cgiirw.github.io/2018/10/14/Blocked02/
1.4.2.3. 实际原值
1、
https://www.javazhiyin.com/24364.html
2、
https://tech.youzan.com/javasuo-yu-xian-cheng-de-na-xie-shi/
1 |
|
1 |
|
2. 面试题
2.1. 底层原理
CompareAndSwap 是一个 native 方法,实际上它最终还是会面临同样的问题,就是 先从内存地址中读取 state 的值,然后去比较,最后再修改。 这个过程不管是在什么层面上实现,都会存在原子性问题。 所以呢,CompareAndSwap 的底层实现中,在多核 CPU 环境下,会增加一个 Lock 指令对缓存或者总线加锁,从而保证比较并替换这两个指令的原子性。
2.2. 应用场景
- 第一个是 J.U.C 里面 Atomic 的原子实现,比如 AtomicInteger,AtomicLong。
- 第二个是实现多线程对共享资源竞争的互斥性质,比如在 AQS、 ConcurrentHashMap、ConcurrentLinkedQueue 等都有用到。
3. 参考与感谢
[[../../../../cubox/006-ChromeCapture/CAS 原理和缺陷 huzb的博客]]
[[../../../../cubox/006-ChromeCapture/探底分析Java原子类CAS的实现原理—从HotSpot源码到CPU指令cmpxchg HeapDump性能社区]]