[Java] CAS

CAS是一种无锁算法,用于保证并发编程中的原子性。AtomicInteger类利用CAS实现线程安全的计数,避免了synchronized的锁竞争。自旋锁是基于CAS的一种乐观锁实现,线程会不断重试直到获取锁。然而,CAS存在ABA问题,即值在比较和交换间可能经历A->B->A的变化。解决方法包括限制值的变更方向或使用版本号来跟踪变化。
摘要由CSDN通过智能技术生成

目录

CAS是什么

标准库中的CAS

二 . 自旋锁(CAS)

三 . CAS 中的ABA问题


CAS是什么

CAS : compare and swap

CAS要做的事情就是 : 拿着寄存器的值和另外一个内存的值 进行比较 , 如果值相同了 , 就把另一个寄存器的值 , 和当前的这个内存的值进行交换.

标准库中的CAS

标准库中的 AtomicInteger 能够保证++ -- 的时候线程安全(保证线程安全的并不是加锁. 而是CAS).

两个线程对变量num分别自增5000次 : 

import java.util.concurrent.atomic.AtomicInteger;

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

 

 利用CAS , 就可以实现上述功能, 既有线程安全 , 而且还比suychronized 更高效, synchronized 会涉及到锁的竞争 , 两个线程都要互相等待 , CAS 不涉及到线程阻塞等待.

另外AtomicInteger 中还有 : 

public static void main(String[] args) {
        AtomicInteger num = new AtomicInteger(0);
        num.getAndIncrement(); // num++;
        num.getAndDecrement(); // num--;
        num.decrementAndGet(); // --num;
        num.incrementAndGet(); // ++num;
    }

AtomicInteger 中的++操作实现过程 : 

CAS本身对应一条cpu指令 (不可拆分的最小单位) , 此时上述的比较和交换动作是没法再拆的!!  具体实现由硬件支持

二 . 自旋锁(CAS)

反复检查当前的锁状态 , 看是否解开了.

我们认为自旋锁是一个轻量级锁 , 也可以视为是一个乐观锁~~

当前这把锁虽然没能立即拿到 , 预期很快就能拿到 , (我们认为锁冲突并不激烈)

虽然一直处于忙等 , 当时短暂的自旋几次, 浪费点cpu, 问题都不大, 自旋锁的好处就是只要这边锁一释放 , 就能立即的拿到锁~

三 . CAS 中的ABA问题

CAS 中的关键 , 是 先比较 , 再交换~~

比较其实是在比较 当前值 和 旧值是不是相同.

把这个两个值相同 , 就视为是中间没有发生过改变.

但是这里的结论才在漏洞, 当前值 和 旧值相同可能是中间确实没改变过 , 也有可能变了 , 但是又变回来了.

在特殊情况下 : 万一对比的时候是相同的, 但是不是没变过 , 而是从 A -> B -> A.

好比是 : 内存中的原本是 A  将过其他的线程改变为B , 又被改为A . 

这样的漏洞 , 在大多数情况下 , 其实没影响 , 但是 , 极端情况下也会引起Bug. 

解决方案有两种 : 

1. 约定数据的值只能单方向变化 , (只能增加或者减小)

2. 如果是既要增加也要减小 , 可以引入另一个版本号 变量 , 约定版本号只能增加(每次修改,都会让版本号更新),

因此只要约定版本号 , 只能递增, 就能保证此时不会出现ABA反复横跳的问题 , 以版本号为基准, 而不是以变量数值为基准了! 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值