Java锁机制通过分段计数(如LongAdder)、自适应自旋、CAS与锁协同(如ReentrantLock、ConcurrentHashMap)及状态标记等策略缓解CAS自旋空转,本质是分流竞争、权衡空转与阻塞、按需选型。

Java 中锁机制本身不直接“解决”CAS自旋空转,而是通过分层设计和组合策略来缓解这个问题——核心思路是:**避免让所有线程挤在同一个CAS变量上死循环,转而用更粗粒度或更智能的协作方式分流竞争**。
用分段计数降低单点竞争
比如 LongAdder 就是典型方案:它内部维护一个 base 值 + 多个 Cell 数组。当 CAS 在 base 上失败时,线程不是继续死磕,而是尝试哈希定位到某个 Cell,对该 Cell 执行 CAS。这样 1000 个线程的更新压力被分散到多个独立变量上,大幅减少单个 CAS 的冲突概率。
- 每个 Cell 是独立的 long 变量,彼此无竞争
- 只有在最终求和(
sum())时才汇总,读操作稍慢但写操作几乎无争抢 - 比
AtomicLong在高并发下吞吐量高出数倍
引入退避与自适应自旋
JVM 和 JUC 并非盲目自旋。例如轻量级锁升级过程中,会采用自适应自旋:如果上次在该锁上自旋成功了,这次就多试几次;如果总失败,就快速放弃、升级为重量级锁并阻塞。
- HotSpot 默认最多自旋 10 次(可通过
-XX:PreBlockSpin调整) - 自旋期间线程仍在用户态运行,不切换上下文,但会插入
pause指令降低 CPU 占用 - 本质是用“少量可控空转”换“避免昂贵阻塞”,权衡而非消除
混合使用锁与 CAS,按场景选型
CAS 不是万能替代品。JUC 中很多类其实是“CAS + 锁”协同工作:
立即学习“Java免费学习笔记(深入)”;
-
ReentrantLock的非公平模式:先 CAS 尝试抢锁,失败再进 AQS 队列排队 -
ConcurrentHashMap:读操作完全无锁(volatile + CAS),写操作则对具体桶加锁(synchronized 或 CAS 控制) - 关键逻辑复杂、涉及多字段更新时,直接用可重入锁更稳妥,不硬套 CAS
用状态标记+CAS规避无效自旋
有些场景可通过提前判断跳过无意义等待。例如在实现自定义锁时,可加一个 volatile 状态位:
- 先读取锁状态,若为“空闲”再发起 CAS;若已是“锁定中”,直接进入等待队列
- 避免线程在锁明显不可用时还空跑几十次 compareAndSet
- 类似 AQS 中
tryAcquire的快速路径设计


















