CAS简述

什么是CAS

        CAS,全称Compare and swap,字⾯意思为⽐较并交换,⼀个CAS涉及到以下操作:

        内存中有数值A,寄存器1中有A,寄存器2中有B

        1,比较内存中数值是否和寄存器中数值相等

        2,如果相等,将另一个寄存器的值写入内存

        3,返回交换是否成功

        如:比较内存和寄存器1中的值,均为A,故将内存中的A和寄存器2中的B交换,返回true.

        伪代码示例

boolean CAS(address, expectValue, swapValue){
        if(address == expectValue){
            address = swapValue;
            return true;
        }
        return false;
    }

CAS是怎么实现的

        针对不同的操作系统,JVM⽤到了不同的CAS实现原理,简单来讲:

java的CAS利⽤的的是unsafe这个类提供的CAS操作
unsafe的CAS依赖了的是jvm针对不同的操作系统实现的Atomic::cmpxchg
Atomic::cmpxchg的实现使⽤了汇编的CAS操作,并使⽤cpu硬件提供的lock机制保证其原⼦

        简⽽⾔之,是因为硬件予以了⽀持,软件层⾯才能做到

CAS的应用

        1.原子类

        在java.util.concurrent.atomic包的类,都是基于CAS方法来实现的,如AtomicInteger类,它的getAndIncrement方法就相当于原子的i++操作,这样不使用锁也可以实现多线程的自增案例.

public static void main(String[] args) throws InterruptedException {
        AtomicInteger atomicInteger = new AtomicInteger();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                atomicInteger.getAndIncrement();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 5000; i++) {
                atomicInteger.getAndIncrement();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(atomicInteger.get());
    }

        2.实现自旋锁

        伪代码实现

public class Lock {
    private Thread owner = null;
    public void lock() {
        //加锁时,如果锁的持有者为空,那么将持有者替换为加锁线程 然后退出
        //如果不为空,那么CAS返回false,while判断为true持续尝试加锁
        while(!CAS(this.owner, null, Thread.currentThread())){
        }
    }
    public void unlock() {
        this.owner = null;
    }
}

CAS的ABA问题

        ABA问题指,一个线程想要通过CAS修改A为其他值,预期为值不变就修改,但是在读取后其他线程将A替换为了B,然后又替换为了A,但是此时值从A变为B又变为A,此时的值被修改过,但是CAS依旧会判断值仍为A不变,修改值.

        bug举例:某人去ATM取钱,卡中余额有1000,要取出500元,点击取款时ATM卡住了,他就点了两次,就会出现两个线程进行CAS修改.线程1读取余额1000后被调走了,线程2正常执行完毕这个CAS操作,扣款500元.当线程2执行完毕后,又有人给他打了500元,此时余额为1000元线程1再开始执行会判断余额为1000再次扣款500元.这样就会出现问题.

        这是CAS进行双向修改(增加和减少)引发的问题.

        解决方案:引入版本号,在读取数值时,不仅读取数值,也要读取数值的版本号,在修改数值时,也要修改数值的版本号,这样就算两次数值相同,版本号也不同,根据版本号不同,判断出不应该进行操作.

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值