当前位置: 首页 > article >正文

CAS简解

CAS 名词解释

  • Compare-And-Swap 比较并替换
  • 它是一条CPU并发原语【原语:属于操作系统语言范畴,它的执行是连续的,不允许被中断的,也就是说CAS是CPU的一条原子指令,不会造成数据不一致的问题】
  • 它的主要功能是判断主内存某个位置的值是否跟预期的值一样,相同就进行修改,否则一直重试,直到一直为止
  • 主要用于实现无锁并发控制,确保在多线程环境对共享变量的操作是原子性

底层操作逻辑

  • 主要在于三个核心参数
    • 内存位置(V) --- 指向要更新遍历的内存地址
    • 预期原值(E) --- 更新前的预期值
    • 新值(N) ----要更新的新值
  • 逻辑
    • 当且仅当内存位置的值与预期的值一致时,该位置的值会更新为新值,否则不进行任何操作

具体使用和示例

  • Java中使用CAS的类: java.util.concurrent.atomic包提供了一系列原子类,如AtomicIntegerAtomicLong等。【注意:atomic类是通过 sun.misc.Unsafe类的底层的CAS操作功能。如:compareAndSwapIntcompareAndSwapLong等方法可以直接在内存地址上执行CAS操作】
  • 示例1:

  • package thread;
     
     
    import java.util.concurrent.atomic.AtomicInteger;
     
     
    public class CASDemo {
     
        public static void main(String[] args) {
     
            AtomicInteger atomicInteger = new AtomicInteger(1);
     
            System.out.println(atomicInteger.compareAndSet(1, 2) + "\t 当前数据 值 : " + atomicInteger.get());
     
            //修改失败
            System.out.println(atomicInteger.compareAndSet(1, 3) + "\t 当前数据 值 : " + atomicInteger.get());
            // 自增并返回当前的atomicInteger值
            atomicInteger.getAndIncrement();
     
        }
    }

底层原理

  • UnSafe类(Native方法) + CAS思想
  • UnSafe类

    • UnSafe类是CAS的核心类,由于Java方法是不能直接操作底层系统的,需要通过本地方法来访问,通过UnSafe类可以直接操作特定内存中的数据
    • UnSafe类中变量使用volatile来修饰,保证了内存的可见性;Atomic的自增就是由于类中的值使用volatile修饰
  • CAS思想(自旋锁)

    • 在使用CAS操作时,当CAS操作失败后,线程不直接阻塞等待,而是继续尝试执行,直到CAS操作成功为止
    • 自旋锁的意思时程序使用循环来等待特定条件的实现方式,先比较传统的阻塞锁,自旋锁不会使线程进入阻塞状态,因此避免了线程上下切换带来的开销。通常当线程竞争的资源空闲等待的时间不长时,自旋锁时一种比较高效的同步机制

优点

  • 无锁并发: CAS操作不需要显示的锁机制,减少了锁竞争的开销,提高了并发性能

缺点

  • ABA问题:如果内存位置的值从A变成B又变回A,那么CAS无法检测出这种变化。可以通过使用带版本号的CAS操作或使用AtomicStampedReference类解决
  • 活锁问题:在最差的情况下,如果比较不成功,线程会一直循环,可能导致性能问题,通常建议使用分段CAS和自动迁移机制来优化
  • 只能保证一个共享变量的原子性操作

ABA问题

分段CAS

所谓CAS分段机制,其维护这一个base变量和一个cell数组,当多个线程操作一个变量的时候,先会在这个base变量上进行cas操作,当它发现线程增多的时候,就会使用cell数组。比如当base更新为3的时候发现线程增多(也就是casBase操作失败),那么它会自动使用cell数组,每一个线程对应于一个cell,在每一个线程中对该cell进行cas操作,这样就可以提高并发效率,分散并发压力

自动迁移机制

当线程增多,每个cell中分配的线程数也会增多,当其中一个线程操作失败的时候,它会自动迁移到下一个cell中进行操作,这也就解决了CAS空旋转,自旋不停等待的问题。这就是自动迁移机制

使用

  • CAS操作本身是不保证内存可见性的。通常需要结合其他机制来保证内存可见性,如:volatitle关键字、synchronized关键字
  • CAS是一种乐观锁机制。具体实现为Unsafe类+自旋,通过Unsafe类提供硬件级别的原子性操作保证了并发安全,加上自旋操作,解决了synchronized在多线程环境下出现的线程阻塞,唤醒切换,以及用户态内核态之间的切换带来的消耗
  • CAS可以不加锁保证操作的原子性,Java标准库提供了Atomic+包装类,相关的组合类来实现原子操作,这些类都在java.util.concurrent.atomic 包底下


http://www.kler.cn/a/516109.html

相关文章:

  • 重构开源LLM分类:从二分到三分的转变
  • 【Knife4j与Swagger的区别是什么?】
  • 【网络协议】【http】【https】TLS解决了HTTP存在的问题-加密通信+摘要,数字签名+CA证书
  • Node.js——express中间件(全局中间件、路由中间件、静态资源中间件)
  • 靶机复现-pikachu靶机文件包含漏洞
  • Android SystemUI——通知栏构建流程(十六)
  • 怎么解决Visual Studio中两个cpp文件中相同函数名重定义问题
  • 【github 使用相关】提交pr和commit message Conventional Commits 规范 代码提交的描述该写什么?
  • 【C++】详细讲解继承(上)
  • 【网络协议】【http】【https】ECDHE-TLS1.2
  • 领域驱动设计(DDD)四 订单管理系统实践步骤
  • 【时时三省】(C语言基础)格式化输入输出函数
  • 2025.1.21——六、BUU XSS COURSE 1
  • P1115 最大子段和
  • 人工智能在音频、视觉、多模态领域的应用
  • 踏浪而行,2024年技术创作的星光轨迹
  • c++瓷砖
  • 4. LwIP_网络数据包管理
  • Spring AI Document
  • 消息队列篇--原理篇--常见消息队列总结(RabbitMQ,Kafka,ActiveMQ,RocketMQ,Pulsar)
  • IoTDB结合Mybatis使用示例(增删查改自定义sql等)
  • electron打包报错解决
  • ThinkPHP 8模型与数据的插入、更新、删除
  • 转换模型到 bfloat16 精度之前需要做的检查工作,不然模型报错给你看
  • Java学习教程,从入门到精通,JDBC创建数据库语法知识点及案例代码(99)
  • SpringBoot读取配置优先级顺序是什么?