CAS能替代锁做限流计数,因其通过CPU原子指令实现无锁的“读-比-写”,避免阻塞与上下文切换,适合高频读、低频写的共享计数场景。

CAS 机制在无锁限流器中实现高并发安全更新计数,核心是“不锁资源、先试后判”:每次更新前读取当前值,用原子比较交换操作尝试写入新值,仅当期间无人改动才成功;失败则重试,直到成功为止。它避免了线程挂起和上下文切换,适合低到中等竞争强度的计数场景。
为什么 CAS 能替代锁做限流计数
限流本质是对一个共享整数(如当前并发请求数)做增减控制。传统 synchronized 或 ReentrantLock 会阻塞其他线程,而 CAS 通过 CPU 级原子指令(如 x86 的 cmpxchg)保证单次读-比-写不可中断:
- AtomicInteger.incrementAndGet() 底层就是循环 CAS:读当前值 v,尝试把 v+1 写入,若内存中仍是 v 就成功,否则重读再试
- 没有锁对象争抢,没有线程调度开销,吞吐更高、延迟更稳
- 适用于“高频读 + 低频写”的限流计数,比如统计当前活跃连接数、令牌桶剩余令牌数
CAS 更新计数的正确写法(避免丢失更新)
直接调用 incrementAndGet 或 decrementAndGet 是最安全的封装,但若需复合逻辑(如“只有小于阈值才加一”),必须手动写 CAS 循环,并注意 old 值必须在循环内实时读取:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- ❌ 错误写法:
int old = counter.get(); atomic.compareAndSwapInt(&counter, old, old + 1);—— old 是快照,可能已过期 - ✅ 正确写法:
while (true) { int old = counter.get(); if (counter.compareAndSet(old, old + 1)) break; } - 若含条件判断(如限流检查),建议用
getAndUpdate或updateAndGet,它们内部已封装 CAS 循环,语义清晰且线程安全
结合限流场景的实际应用要点
在令牌桶或并发数控制器中,CAS 更新不能孤立使用,需配合业务逻辑设计:
立即学习“Java免费学习笔记(深入)”;
- 令牌桶 refill 操作通常用定时任务+原子更新,获取令牌时用
getAndUpdate(v -> v > 0 ? v - 1 : 0),一行代码完成“有则扣、无则归零” - 全局并发限流器中,acquire() 对计数器原子加一并比较是否超限;release() 原子减一 —— 这两个操作都必须是无条件 CAS,不可拆成 get+set
- 高竞争下(如每毫秒数千请求),纯 CAS 自旋可能浪费 CPU,此时应考虑退化策略:比如连续失败 N 次后短暂让出线程(
Thread.onSpinWait()),或改用 Semaphore 控制许可数(它底层也基于 AQS + CAS,但做了排队优化)
不复杂但容易忽略的是:CAS 安全的前提是操作目标为单一变量、无外部依赖。一旦涉及多个变量协同(如“扣令牌 + 记日志 + 更新缓存”),就必须升级为锁或事务机制,不能硬套 CAS。

















