「这是我参与 11 月更文挑战的第 11 天,活动详情查看:2021最后一次更文挑战」。
你好,我是悟空呀。今天给大家带来的大厂面试题是:
并发编程中的 CAS 原理知道吗?
原子整型类 AtomicInteger 的 getAndIncrement 方法就用到 CAS。
比如这一段代码:
atomicInteger.compareAndSet(10, 20);Copy to clipboardErrorCopied
调用 atomicInteger 的 CAS 方法,先比较当前变量 atomicInteger 的值是否是10,如果是,则将变量的值设置为20。
- CAS 的全称:Compare-And-Swap(比较并交换)。比较变量的现在值与之前的值是否一致,若一致则替换,否则不替换。
- CAS 的作用:原子性更新变量值,保证线程安全。
- CAS 指令底层代码:需要有三个操作数,变量的当前值(V),旧的预期值(A),准备设置的新值(B)。
- CAS 指令执行条件:当且仅当 V=A 时,处理器才会设置 V=B,否则不执行更新。
- CAS 的返回值:V 的之前值。
- CAS 处理过程:原子操作,执行期间不会被其他线程中断,线程安全。
- CAS 并发原语:体现在 Java 语言中 sun.misc.Unsafe 类的各个方法。调用 UnSafe 类中的 CAS 方法,JVM 会帮我们实现出 CAS 汇编指令,这是一种完全依赖于硬件的功能,通过它实现了原子操作。由于 CAS 是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,所以 CAS 是一条 CPU 的原子指令,不会造成所谓的数据不一致的问题,所以 CAS 是线程安全的。
CAS 带来的问题:
1)频繁出现自旋,循环时间长,开销大(因为执行的是do while,如果比较不成功一直在循环,最差的情况,就是某个线程一直取到的值和预期值都不一样,这样就会无限循环)
2)只能保证一个共享变量的原子操作
- 当对一个共享变量执行操作时,我们可以通过循环CAS的方式来保证原子操作
- 但是对于多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候只能用锁来保证原子性。