选CAS还是synchronized取决于竞争强度、操作粒度和场景特征:低竞争单变量用CAS更轻快,高竞争复合操作用synchronized更稳,且需结合JDK成熟并发工具合理选用。

选 CAS 还是 synchronized,关键看竞争强度、操作粒度和场景特征,不是谁“高级”就用谁,而是谁更贴合实际。
看竞争是否频繁
低竞争时 CAS 更轻快:比如配置项读取、计数器累加(如 PV 统计),线程很少同时改同一个值,CAS 自旋几轮就能成功,避免了锁的挂起/唤醒开销。
高竞争时 synchronized 更稳:比如库存扣减、订单支付,多个线程反复抢同一把锁,CAS 会陷入长自旋,CPU 空转严重,此时 JVM 的锁升级机制(偏向→轻量→重量)反而能通过合理阻塞降低资源浪费。
看操作是否单变量原子
CAS 只能保证单个变量的原子更新:AtomicInteger、AtomicReference 底层靠 compareAndSet 实现 i++ 或引用替换,干净利落。
涉及多步逻辑就必须用 synchronized:比如“先查余额、再判断是否足够、再扣款、再写日志”,这四步必须整体原子,CAS 无法覆盖,强行拆成多个 CAS 容易出 ABA 或状态不一致问题。
看是否需要锁的扩展能力
synchronized 天然支持可重入、内存可见性、happens-before 语义,且与 JVM 深度协同(如锁消除、锁粗化);
在调试 Java 后端 API 故障时使用此技能,尤其适用于以下任务:分析日志、跨 Controller、Service 和 Mapper 层追踪请求、定位异常根因、检查 SQL 执行或参数流转,以及生成简洁的诊断结论与修复方案。
CAS 没有等待队列、不支持条件等待(await/signal)、无法实现公平策略,也没法像 ReentrantLock 那样尝试获取(tryLock)、超时获取或响应中断。
- 要中断等待?→ 用 ReentrantLock(它底层也混合用了 CAS + 阻塞队列)
- 要读多写少的并发结构?→ 用 ReentrantReadWriteLock(读锁共享,写锁互斥)
- 只是简单计数或状态标记?→ AtomicInteger 或 AtomicBoolean 就够了
看是否已有成熟封装
别自己手写 CAS 循环:ConcurrentHashMap、LongAdder、StampedLock 等 JDK 并发工具类,已经针对不同场景做了充分优化。比如 LongAdder 在高并发累加时比 AtomicInteger 更快,就是因为它用分段 CAS + 最终汇总,避开热点变量竞争。
同样,synchronized 在 JDK 1.6+ 后已不是“重量级”代名词——90% 以上场景走的是偏向锁或轻量级锁路径,开销远低于早期认知。
真正卡点不在“用哪个”,而在“用得对不对”:低频单变量更新硬上 synchronized 是浪费,高频复合操作只靠 CAS 是冒险。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










