longadder通过分段计数(base+cells数组)分散cas竞争,避免伪共享,吞吐量达atomiclong的3–5倍;结合threadlocal批量提交与最终一致性设计,进一步降低冲突;必要时可动态切回synchronized兜底。

CAS 机制本身不降低锁竞争——它根本不用锁。问题核心在于:高并发计数器性能差,不是因为“锁太重”,而是所有线程挤在同一个内存地址上反复 CAS 失败,造成自旋风暴和缓存行失效。真正的优化方向是分散竞争,而不是调优 CAS 指令本身。
用 LongAdder 分段替代单点 CAS
AtomicLong 只维护一个 volatile long 和一次 CAS,100 个线程同时 increment,大概率 90+ 次失败重试。LongAdder 改为 base + cells 数组结构:
- 初始无竞争时,直接 CAS 更新 base,开销等同 AtomicLong
- 首次 CAS 失败后,懒初始化 cells 数组(默认长度 2),线程按哈希值定位到专属 Cell
- 每个 Cell 是独立对象,字段内存地址不同,天然避开伪共享;JDK8+ 还用 @Contended 自动填充隔离
- 写操作分散到多个地址,冲突概率大幅下降,吞吐量可达 AtomicLong 的 3–5 倍
结合 ThreadLocal 批量提交,进一步降频
连 Cell 级别都嫌争抢多?那就让线程完全不碰共享内存:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 每个线程持有一个 ThreadLocal
,本地 increment 零竞争 - 累积达阈值(如 100 次)或定时(如每 10ms),再把本地和批量 add 到全局 LongAdder
- 全局写入频率下降两个数量级,CAS 几乎不再失败,CPU 空转趋近于零
接受最终一致性,避免读写互相拖累
计数器多数用于监控、限流、采样,不需要每毫秒都精确:
- LongAdder.sum() 是只读遍历,不参与任何 CAS,不影响写性能
- 返回的是 base 加所有非空 cell 的快照和,可能比最新值慢几微秒——但业务通常可接受
- 若硬要强一致,反而得退回 AtomicLong,付出吞吐量代价
必要时动态兜底,不迷信纯无锁
极端场景下,持续高失败率说明分段仍不够用:
- 监控每秒 CAS 失败次数,超阈值(如 1000 次/秒)时临时切为 synchronized 块执行 increment
- 几秒后无失败,自动切回 LongAdder 模式
- 这种“无锁优先、有锁兜底”的弹性策略,比死守一种模型更贴近真实流量波动
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










