cas通过自旋代替阻塞,在用户态完成原子操作,避免上下文切换开销;适用于读多写少场景,高冲突时需退化为悲观锁或采用longadder等优化策略。

CAS 通过“不阻塞、不挂起”的方式绕开操作系统级的线程调度,直接在用户态完成原子操作,从而避免悲观锁引发的上下文切换开销。
核心机制:用自旋代替阻塞
悲观锁(如 synchronized 或 ReentrantLock)在竞争失败时,会将线程挂起,交由操作系统调度——这触发用户态到内核态切换、保存/恢复寄存器与栈、更新调度队列等动作,开销显著。CAS 不走这条路:
- 线程发现值被修改后,不放弃 CPU,而是立即重试(自旋),继续读取当前值并再次比较交换;
- 整个过程停留在用户态,不涉及线程状态变更(RUNNABLE → BLOCKED/WAITING),也无需内核介入;
- 适合短时间、低冲突场景,一次或几次自旋就能成功,CPU 空转成本远低于一次上下文切换(通常耗时几十到上百纳秒 vs 微秒级)。
典型应用:原子类天然规避锁调度
AtomicInteger、AtomicLong、AtomicReference 等底层全部基于 Unsafe 的 CAS 指令实现,例如:
getAndIncrement() 方法本质是循环调用 compareAndSwapInt(),直到成功为止。它没有 lock/unlock、没有 AQS 队列、没有 park/unpark 调用——也就彻底跳过了线程挂起与唤醒环节。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
对比 ReentrantLock 的 tryLock() 失败后若走 lock(),就会进入 AQS 队列并可能 park 当前线程,引发上下文切换。
注意边界:高冲突时自旋反而成负担
CAS 并非万能,它的“零切换”优势依赖于实际并发写入频率:
- 读多写少(如计数器、状态标记):自旋次数少,CPU 利用率可控,吞吐量明显优于悲观锁;
- 写多且高度竞争(如高频抢购扣减):线程反复 CAS 失败→自旋→再失败,造成大量无效 CPU 占用,此时应考虑退化为悲观锁,或改用 LongAdder(分段累加,降低单点竞争);
- ABA 问题虽不直接导致上下文切换,但可能引发逻辑错误,需配合 AtomicStampedReference 使用版本戳来保障正确性。
配合策略:减少自旋浪费,提升实际效率
单纯依赖原始 CAS 容易陷入“忙等”,Java 并发包提供了更务实的组合方案:
- LongAdder 在高并发累加场景下比 AtomicInteger 更高效:它把一个 long 拆成多个 Cell,写操作分散到不同缓存行,大幅降低 CAS 冲突概率;
- ConcurrentHashMap 的 put 操作结合了 CAS + synchronized(仅对桶头加锁),既避免全局锁,又防止极端情况下的长时自旋;
- 某些场景可混合使用:先尝试 CAS 快速路径,失败后降级为轻量级锁或队列等待,平衡响应性与资源消耗。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










