欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

面试总结二:对CAS的理解

程序员文章站 2024-02-25 10:40:35
...

本节内容综述如下:

面试总结二:对CAS的理解

CAS是什么?

CAS是什么? ===》 compareAndSwap 比较并交换

package thread.CAS;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * CAS是什么? ===》 compareAndSet 比较并交换
 *
 */
public class CASDemo {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(5);

        //main do thing.....

        System.out.println(atomicInteger.compareAndSet(5, 2019)+"\t current data: "+atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(5, 1024)+"\t current data: "+atomicInteger.get());


atomicInteger.getAndIncrement();


    }
}

CAS全称 compare-and-swap ,cpu并发原语。执行是连续的,不允许被中断,不会造成数据不一致问题。它的功能是判断内存某一个位置的值是否为预期,如果是则更改这个值,这个过程就是原子的。

 

CAS并发原语体现在JAVA 语言中就是 sun.misc.Unsafe 类中的各个方法。调用 UnSafe 类中的 CAS 方法,JVM 会帮我们实现出 CAS 汇编指令。这是一种完全依赖硬件的功能,通过它实现了原子操作。由于 CAS 是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成,用于完成某一个功能的过程,并且原语的执行必须是连续的,在执行的过程中不允许被中断,也就是说 CAS 是一条原子指令,不会造成所谓的数据不一致的问题。

 

 

cas底层原理?如果知道,谈谈你对UnSafe的理解

0、综述:

CAS比较并交换就是unsafe类和自旋锁

 

unsafe类是方法都是有native修饰的调用底层资源,java 中CAS关键代码unsafe.getAndAddInt()方法,里面有个do while 结构的自旋锁:

 

do里面有this.getIntVolatile(var1,var2);获取当前主内存的值var1指代当前对象,var2指代 对象地址

然后再while里面游走个判断,compareAndSwapInt(…)比较并交换 就是重新取值 和do里面取得值作比较,相同返回,不同重新比较,循环。

cas优点:不加锁,相比于synchronized效率高,解决了原子性

cas缺点:大并发下会循环比较,会导致ABA问题

 

 

 

1、atomicInteger.getAndIncrement()方法的源代码

面试总结二:对CAS的理解

(其中:变量value被volatile修饰,保证了多线程之间的可见性)

变量ValueOffset,便是该变量在内存中的偏移地址,因为UnSafe就是根据内存偏移地址获取数据的偏移地址

 

2、UnSafe类:UnSafe类是CAS的核心类,位于sun.misc.Unsafe。由于Java方法无法直接访问底层 ,需要通过本地(native)方法来访问。

面试总结二:对CAS的理解

通过调用UnSafe 类中的CAS 方法(其内部方法操作通过C的指针直接操作系统内存),JVM会帮我们实现出CAS汇编指令,基于该类可以直接操作特额定的内存数据。(这是一种完全依赖硬件的功能,通过它实现了原子操作。)

注意UnSafe类中所有的方法都是native修饰的,也就是说UnSafe类中的方法都是直接调用操作底层资源执行响应的任务

 

面试总结二:对CAS的理解

 

3、Unsafe类中的compareAndSwapInt方法

(以下为汇编指令解释:)

在x86 平台上,CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin,如果汇编语言的程序中在一条指令前面加上前缀'LOCK',经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低,持续到这条指令结束时放开,从而把总线锁住,这样同一总线上别的CPU就暂时不能通过总线访问内存了,保证了这条指令在多处理器环境中的原子性。

面试总结二:对CAS的理解

 

最后总结:一图流

面试总结二:对CAS的理解

 

CAS 的缺点?

循环时间长开销很大:

如果 CAS 失败,会一直尝试,如果 CAS 长时间一直不成功,可能会给 CPU 带来很大的开销(比如线程数很多,每次比较都是失败,就会一直循环),所以希望是线程数比较小的场景。

只能保证一个共享变量的原子操作。

 

对于多个共享变量操作时,循环 CAS 就无法保证操作的原子性。

 

引出 ABA 问题。

 

原子类 AtomicInteger 的 ABA 问题谈一谈?原子更新引用知道吗?