CAS底层原理

我们以这段代码为例进行讲解:


class MyData{

    AtomicInteger atomicInteger = new AtomicInteger();

    public void addMyAtomic(){
        atomicInteger.getAndIncrement();
    }
}


public class VolatileDemo {


    public static void main(String[] args) {
        MyData myData = new MyData();
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int j = 0; j < 1000; j++) {
                    myData.addPlusPlus();
                    myData.addMyAtomic();
                }
            },String.valueOf(i)).start();
        }

        //需要等待上面20个线程全部计算完成后,再用main线程取得最终的结果看是多少
        while (Thread.activeCount() > 2){
            Thread.yield();
        }

        System.out.println(Thread.currentThread().getName() + "\t AtomicInteger type,finally number value:" + myData.atomicInteger);
    }
}

上面得出来的结果是20000,那么 getAndIncrement()方法是如何保证原子性的呢?我们还是有些不太理解。

那么接下来我们就提出原语这个词

CAS的全称为Compare-And-Swap,它是一条CPU并发原语它的功能是判断内存某个位置是否为预期值,如果是则更新为新的值,这个过程是原子的。

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

CAS并发原语的特点

我们先来看一下它的底层实现:

Unsafe类中的compareAndSwapInt,是一个本地方法,该方法的实现位于unsafe.cpp中,该方法中的Atomic::cmpxchg(x,addr,e) ==e;实现比较替换(参数x是即将更新的值,参数e是原内存的值)

缺点:

1.循环时间长开销大(多个线程一直循环CPU飙高)

2.只能保证一个共享变量的原子操作(this+偏移量指定的那个变量)

3.ABA问题

总结:CAS比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则继续比较直到主内存和工作内存中的值一致为止。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值