Java面试题(十一)CAS和ABA问题

本文通过一个具体的多线程测试案例,对比了AtomicInteger与普通整型变量在并发环境下的表现,深入剖析了CAS(Compare And Swap)的工作原理及其优缺点,并讨论了ABA问题及解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先来看一段代码

private static AtomicInteger atomicInteger = new AtomicInteger(0);
private static int m = 0;
public static void main(String[] args) throws Exception{
    Thread [] threads = new Thread[100];
    CountDownLatch latch = new CountDownLatch(threads.length);
    for(int i = 0; i < threads.length; i ++){
        threads[i] = new Thread(()->{
            for (int j = 0; j < 100; j++) {
                atomicInteger.incrementAndGet();
                m ++;
            }
            latch.countDown();
        });
    }

    Arrays.stream(threads).forEach((t)->{
        t.start();
    });
    latch.await();
    System.out.println("----------atomic int--------" + atomicInteger);
    System.out.println("----------for int--------" + m);
}

在这里插入图片描述
现在有100个线程,每个线程循环100次,进行+1操作,同时操作atomicInteger 和 m这2个静态变量
从结果可以看出,使用JUC 下面的atomic能够得到目标值,而变量m 的结果并不是1W,原因肯定是多线程执行没有上锁,导致某一时刻有N个线程同时+1

那么为什么atomic没上锁,最后的结果却是1W呢?

什么是CAS

CAS(Compare And Swap)是指比较并交换。CAS算法 CAS(V,E,N)包含有3参数,V 表示要更新的变量,E 表示预期的值,N 表示新值。

在这里插入图片描述

这里画了个图,通过这个图很直观的就能知道CAS的处理逻辑,这里面实际上并没有任何的加锁操作,每次操作之前都会先进行比较,然后在替换,如果不相等,就会一直循环的执行下去,直到最终执行成功,这样是他为什么会被称为自旋锁;当然CAS也是一种乐观锁,总是认为自己是可以成功完成操作的。在有多个线程可以同时使用 CAS 操作一个变量时,只有一个会胜出并成功更新,其余均会失败。

CAS的缺点

  1. 自旋的时候会一直循环,会导致CPU高负荷
  2. 只能保证变量的原子性,并不能像Synchronized那样添加到方法上或者代码块上
  3. ABA问题

什么是ABA问题?

接着上面所说,当线程A在拿到m=0,进行+1操作的时候,此时有个线程B 进来他把m修改成1,然后又修改成0,此时线程A在进行比较的时候,虽然m这个值还是0,但是是被人修改过后的0,不是之前的那个0了,这就是ABA问题,A–>B–>A,如何解决?

  • 添加时间戳
  • 添加版本号
  • 使用悲观锁Synchronized
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

珍妮玛•黛金

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值