CAS操作的底层原理(总线锁定机制和缓存锁定机制 )

目录

处理器级别的实现

总线锁定机制

缓存锁定机制

MSEI表示缓存行的四种状态

MESI协议状态转换

CAS操作是不保证可见性的

CAS基本概念

ABA问题的处理

性能考虑


先总结一下,CAS(Compare And Swap)是一种原子操作,它比较当前内存值与期望值,如果相等则更新为新值,CAS是一种硬件级的原子操作,通过总线锁或缓存锁实现原子性,在使用缓存锁的时候缓存一致性协议保证数据一致性。

而Java通过native方法调用底层CAS指令,需要考虑ABA问题和性能优化,而cas这种机制保证了在多处理器系统中的原子操作,是实现无锁并发的基础。

处理器级别的实现

x86汇编中的CMPXCHG指令示例

lock cmpxchg [内存地址], 新值

处理器通过特殊的指令(如x86的CMPXCHG)来实现CAS操作,并使用LOCK前缀保证操作的原子性。

总线锁定机制

CPU1 ----┐

CPU2 ----├── 总线 -----> 内存

CPU3 ----┘

LOCK信号

当一个CPU发出LOCK信号时,其他CPU无法通过总线访问内存,保证了操作的原子性。但这种方式开销较大。

缓存锁定机制

CPU1 Cache [数据A: M] ─┐

CPU2 Cache [数据A: I] ─┼── 总线 ──> 内存[数据A]

CPU3 Cache [数据A: I] ─┘

使用缓存一致性协议(MESI),通过缓存状态控制来保证原子性,效率更高。

MSEI表示缓存行的四种状态

M(Modify)表示共享数据只缓存在当前 CPU 缓存中, 并且是被修改状态,也就是缓存的数据和主内存中的数据不一致

E(Exclusive)表示缓存的独占状态,数据只缓存在当前 CPU 缓存中,并且没有被修改

S(Shared)表示数据可能被多个 CPU 缓存,并且各个缓存中的数据和主内存数据一致

I(Invalid)表示缓存已经失效

MESI协议状态转换

CPU1执行CAS:

  1. 发出监听请求

  2. 等待其他CPU响应

  3. 确认无冲突后执行

  4. 广播状态变更

CPU在读取一个数据时会先发起监听,去监听其他CPU的对这个数据缓存行的状态。

如果本CPU缓存行状态是I,则需要从内存中读取,并把缓存行状态置为S。

如果本CPU缓存行的状态不是I,则可以直接读取缓存中的值,如果其他CPU也有该数据的缓存且状态是M,则需要等待其把缓存更新到内存后再读取。

CPU更新了缓存行的状态了之后会发广播来更新其他CPU的缓存行状态。

CAS操作是不保证可见性的

这一点要特别注意,CAS的操作是不保证可见性的,可见性是实现CAS操作的前提,如果连可见性都保证不了,这又怎么实现CAS操作?

CAS操作通常与volatile配合使用,通过内存屏障保证可见性。

CAS基本概念

java 复制代码
// CAS操作的伪代码
public boolean compareAndSet(int expectedValue, int newValue) {
    // 原子操作,比较并交换
    // V是要更新的变量,E是期望值,N是新值
    if (V == expectedValue) {
        V = newValue;
        return true;
    }
    return false;
}

CAS(Compare And Swap)是一种原子操作,它比较当前内存值与期望值,如果相等则更新为新值。

ABA问题的处理

java 复制代码
public class AtomicStampedReference<V> {
    private static class Pair<T> {
        final T reference;
        final int stamp;
        
        private Pair(T reference, int stamp) {
            this.reference = reference;
            this.stamp = stamp;
        }
    }
}

ABA是CAS操作的经典问题了,可以通过版本号或时间戳解决ABA问题。

性能考虑

java 复制代码
// 自旋等待示例
public void spinLock() {
    while (!cas.compareAndSet(false, true)) {
        // 自旋等待
        Thread.onSpinWait(); // Java 9+
    }
}

CAS失败时通常采用自旋等待,需要考虑自旋次数和退避策略。

相关推荐
团子的二进制世界1 分钟前
G1垃圾收集器是如何工作的?
java·jvm·算法
long3165 分钟前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法
rannn_11132 分钟前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
灵感菇_34 分钟前
Java HashMap全面解析
java·开发语言
qq_124987075336 分钟前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
短剑重铸之日42 分钟前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
若鱼19191 小时前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
觉醒大王1 小时前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
努力学编程呀(๑•ี_เ•ี๑)1 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
码农小卡拉2 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot