15.CAS,原子引用

深入理解CAS

什么是CAS

public class Demo01 {

    //CAS compareAndSet:比较并交换
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //如果期望值达到了就更新,否则就不更新
        atomicInteger.compareAndSet(2020, 2021);
        System.out.println(atomicInteger.get());
        System.out.println(atomicInteger.compareAndSet(2020, 2022));//false
    }
}

Unsafe类

CAS:比较当前工作内存中的值和主内存中的值,如果是期望的。那么则执行操作!不是就一直循环(自旋锁)

缺点:

  1. 循环会耗时
  2. 一次性只能保证一个共享变量的原子性
  3. 存在ABA问题

CAS:ABA问题(狸猫换太子)

图示:A的值其实已经是改变过了的,但左边线程不知道

public class Demo01 {

    //CAS compareAndSet:比较并交换
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(2020);
        //如果期望值达到了就更新,否则就不更新
        //捣乱的线程,2020->2021->2020
        atomicInteger.compareAndSet(2020, 2021);
        System.out.println(atomicInteger.get());
        atomicInteger.compareAndSet(2021, 2020);//false
        System.out.println(atomicInteger.get());
        //期望的线程
        atomicInteger.compareAndSet(2020, 6666);
        System.out.println(atomicInteger.get());//6666
    }
}

原子引用

带版本号的原子操作,解决了ABA的问题,乐观锁的思想。干什么都不加锁,比较版本

public class Demo02 {
    public static void main(String[] args) {
        //初始值,版本
        AtomicStampedReference<Integer> reference = new AtomicStampedReference<>(10, 1);
        new Thread(() -> {
            System.out.println("A1==>" + reference.getStamp());
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reference.compareAndSet(10, 20, reference.getStamp(), reference.getStamp() + 1);
            System.out.println("A2==>" + reference.getStamp());

            reference.compareAndSet(20, 10, reference.getStamp(), reference.getStamp() + 1);
            System.out.println("A3==>" + reference.getStamp());

        }, "A").start();

        //和乐观锁原理相同
        new Thread(() -> {
            int stamp = reference.getStamp();
            System.out.println("B1==>" + stamp);
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //B线程获取到的值虽然是初始值10,但版本显然不是初始版本1,已经为3,是被修改过的,所以这里修改失败
            System.out.println(reference.compareAndSet(10, 100, stamp, stamp + 1));
            System.out.println("B2==>" + reference.getStamp());
        }, "B").start();
    }
}
posted @   jpy  阅读(6)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示