Java CASCompare-And-Swap深度解析无锁并发编程的基石一、 CAS概述从检查-执行到检查-执行-原子化1.1 什么是CAS1.2 为什么需要CAS1.3 CAS的核心特征二、 流程图CAS操作核心流程与多线程竞争场景三、 CAS在Java中的应用3.1 原子类Atomic——CAS的经典封装3.2 自旋锁 ——基于CAS实现轻量级锁3.3 无锁并发数据结构四、 流程图CAS的ABA问题与解决方案4.1 ABA问题详解4.2 解决方案AtomicStampedReference五、 CAS的优缺点与总结5.1 优点5.2 缺点5.3 一句话总结The Begin点点关注收藏不迷路⬇ ⬇ 底部 ⬇ ⬇本文导读本文将深入讲解Java中CASCompare-And-Swap操作的核心概念、底层实现原理、经典应用场景以及ABA问题的解决方案帮助你在无锁编程中游刃有余。全文包含四大核心章节、3个彩色流程图、7个代码示例。预计阅读时间25分钟。一、 CAS概述从检查-执行到检查-执行-原子化1.1 什么是CASCASCompare-And-Swap比较并交换是一种用于实现无锁Lock-Free并发的硬件级原子操作。它的执行逻辑可以概括为三个操作数内存位置V要操作的变量地址预期值A线程认为该变量当前应该持有的值更新值B希望将变量更新成的值执行逻辑只有当内存位置V的当前值与预期值A相等时才将V的值更新为B。如果V的值不等于A则不做任何更新。无论是否更新CAS操作都会返回V的旧值。整个比较和交换过程是原子的由CPU指令直接支持。简单来说CAS就像在修改文档前先检查“这是否是我刚才看到的版本”——如果是就修改如果不是说明别人已改过我放弃修改并准备重试。1.2 为什么需要CAS传统的synchronized和Lock属于悲观锁策略假定会发生并发冲突因此在访问资源前先加锁阻塞其他线程。这种方式在低并发时性能尚可但在高并发下会导致大量的上下文切换和线程挂起/恢复开销。CAS提供了另一种思路——乐观锁假定大多数情况下没有并发冲突因此不加锁直接尝试操作只有在冲突发生时预期值与实际值不符才重试。这种非阻塞的特性使其在高并发场景下性能远超重量级锁。1.3 CAS的核心特征CAS操作 原子性 非阻塞 硬件支持 自旋重试由CPU指令保证不可分割无锁等待不会死锁cmpxchg指令硬件级原语失败时循环重试直到成功硬件级原语CAS依赖CPU提供的原子指令如x86的cmpxchg在硬件层面保证了比较和交换的原子性。二、 流程图CAS操作核心流程与多线程竞争场景相等不相等是否 线程执行CAS操作 读取当前值 V从主内存读取变量 判断 V 预期值 A? 执行原子交换V ← B 操作失败返回V的旧值✅ 更新成功可进行后续操作❌ 更新失败由调用者决定是否重试自旋重试? 重新读取最新值更新预期值A⚪ 放弃操作或执行降级逻辑三、 CAS在Java中的应用3.1 原子类Atomic——CAS的经典封装java.util.concurrent.atomic包下的原子类如AtomicInteger、AtomicLong等是CAS在Java中最典型的应用。// AtomicInteger 内部使用CASAtomicIntegeratomicIntnewAtomicInteger(0);// incrementAndGet() 内部通过CAS自旋实现atomicInt.incrementAndGet();// 每次1// 模拟CAS操作intcurrentatomicInt.get();while(!atomicInt.compareAndSet(current,current1)){currentatomicInt.get();// 失败则重试}3.2 自旋锁 ——基于CAS实现轻量级锁一个简单的自旋锁实现展示了CAS如何代替synchronized// 自定义自旋锁publicclassSpinLock{privatefinalAtomicReferenceThreadownernewAtomicReference();publicvoidlock(){ThreadcurrentThread.currentThread();// CAS自旋直到成功将owner从null设置为当前线程while(!owner.compareAndSet(null,current)){// 空循环等待不释放CPU自旋}}publicvoidunlock(){ThreadcurrentThread.currentThread();// 只有当前持有锁的线程才能释放owner.compareAndSet(current,null);}}3.3 无锁并发数据结构CAS是无锁并发数据结构的核心如ConcurrentHashMap中的节点插入和ConcurrentLinkedQueue的入队/出队操作。四、 流程图CAS的ABA问题与解决方案 ABA解决方案 AtomicStampedReference引入版本号 CAS比较: 值和版本号 版本号变则失败✅ 正确识别中间变化 ABA问题 线程1读: A 线程2: A→B→A 线程1CAS检查: AA 线程1误以为未变化❌ 更新成功, 但数据已变!4.1 ABA问题详解ABA问题是CAS的一个经典陷阱线程T1读取内存位置V的值为A线程T2将V的值改为B又改回A线程T1执行CAS发现V的值仍为A认为数据未变执行更新但V实际上已经被修改过两次T1的更新可能基于过期的假设4.2 解决方案AtomicStampedReference// 带版本号的引用解决ABAAtomicStampedReferenceStringrefnewAtomicStampedReference(A,0);int[]stampHoldernewint[1];Stringvalueref.get(stampHolder);// 同时比较值和版本号ref.compareAndSet(value,B,stampHolder[0],stampHolder[0]1);五、 CAS的优缺点与总结5.1 优点优点说明高性能非阻塞无锁无上下文切换开销无死锁不使用互斥锁不会发生死锁轻量级直接操作内存无需内核介入5.2 缺点缺点说明ABA问题值虽未变但语义已变需用AtomicStampedReference自旋开销高竞争下CAS频繁失败造成CPU空转单变量限制只能操作一个内存变量语义表述困难复杂的共享对象更新逻辑难以用CAS优雅表达5.3 一句话总结CAS是Java无锁并发编程的基石它利用CPU原子指令实现比较-交换一体化操作既避免了锁的开销又保证了线程安全但它并非万能需要在使用时规避ABA问题和自旋开销。The End点点关注收藏不迷路⬆ ⬆ 顶部 ⬆ ⬆