说下CAS的实现与原理?

 CAS是一种原子操作,用于在多线程环境下解决竞争问题。它的核心思想是:只有当内存中的值与预期值相等时,才会将内存中的值更新为新值。
  CAS操作的三个参数
   1.内存值(V):当前内存中的值。
   2.预期值(E):线程期望内存中的值。
   3.新值(N):需要更新的值。
  CAS的操作逻辑
   如果内存值(V)等于预期值(E),则将内存值更新为新值(N)。
   如果内存值(V)不等于预期值(E),则说明其他线程已经修改了内存值,当前线程的更新失败。
 CAS的实现原理
  硬件支持
   CAS的实现依赖于 CPU 的原子指令,例如:
    x86 架构:CMPXCHG指令(Compare and Exchange)。
    ARM 架构:LDREX/STREX指令。
  这些指令可以在硬件层面保证比较和更新操作的原子性,避免了线程切换或中断导致的竞争问题。
  软件实现
   在高级语言中,CAS通常由底层的硬件指令封装实现。例如:
    Java:Java 的 Unsafe 类提供了CAS操作。
    AtomicInteger、AtomicLong 等类都基于CAS实现。
    C++:使用 std::atomic 提供的compare_exchange方法。
    操作系统:Linux 内核中使用cmpxchg实现原子操作。
 CAS的优点
  1.无锁操作:
   a.CAS是一种无锁操作,不需要加锁即可实现线程安全,避免了锁带来的上下文切换和性能开销。
  2.高性能:
   a.CAS操作直接依赖于硬件指令,性能非常高,适合高并发场景。
  3.简单易用:
   a.CAS的逻辑简单,适合实现原子变量、线程安全的计数器等。
 CAS的缺点
  1. ABA问题
   问题描述:如果一个线程读取到的值是A,在准备更新时,另一个线程将值从A改为B,然后又改回A。此时,CAS 操作会认为值没有变化,更新成功,但实际上值已经被其他线程修改过。
   解决方法:使用版本号或时间戳来标记值的变化。例如:将值从A改为A1,再改为A2,通过版本号区分不同的状态。比如Java的 AtomicStampedReference 就是为了解决ABA问题设计的。
  2. 自旋开销
   问题描述:如果CAS操作失败,线程会不断重试(自旋),直到成功。这种情况下,CPU会被占用,导致性能下降。
   解决方法:限制自旋次数,或者在高竞争场景下使用锁代替CAS。
  3. 只能保证一个变量的原子性
   问题描述:CAS只能对单个变量进行原子操作,无法直接保证多个变量的原子性。
   解决方法:使用锁,或者将多个变量封装为一个对象,通过CAS操作整个对象。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容