cas在atomicinteger中是通过volatile value保证可见性、valueoffset定位内存地址、unsafe.compareandswapint调用cpu原子指令实现的乐观无锁更新,全程用户态自旋重试。

Java 中 CAS 机制在 AtomicInteger 底层不是“封装逻辑”,而是直接调用 CPU 级原子指令,靠 volatile 字段 + 字段偏移量 + Unsafe.compareAndSwapInt 三者硬协同实现。整个过程不依赖锁,也不进内核态,是典型的乐观无锁更新。
volatile value 保证每次读都是最新值
AtomicInteger 内部定义了一个 private volatile int value。volatile 关键字有两个作用:
- 禁止指令重排序,确保初始化后 value 对所有线程可见
- 每次读取都从主内存加载,避免线程使用本地缓存的旧值导致 CAS 比较失败
没有它,一个线程刚写入新值,另一个线程还拿着旧值去 compare,CAS 就会反复失败。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
valueOffset 定位字段真实内存地址
Java 对象在堆中是连续内存块,但字段位置不固定。JVM 在类加载阶段通过静态块计算出 value 字段相对于对象起始地址的偏移量:
valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"))- 这个 long 类型的偏移量会被后续所有 CAS 操作复用
- Unsafe 就靠它精准找到 value 在内存中的“格子”,跳过 JVM 普通字段访问路径
Unsafe.compareAndSwapInt 执行原子比较替换
这是真正落地 CAS 的 native 方法:
- 签名是
compareAndSwapInt(Object obj, long offset, int expected, int x) - JVM 会将其编译为一条 CPU 指令(如 x86 平台的
cmpxchg),由硬件保证“读-比-写”不可分割 - 比如
incrementAndGet()的核心就是循环调用它:先读当前值 → 加 1 → 尝试 CAS 更新 → 失败就重读重试
自旋重试是 CAS 正常工作方式
CAS 本身不阻塞,失败后由上层逻辑决定是否继续:
-
getAndIncrement()底层是unsafe.getAndAddInt(this, valueOffset, 1),内部就是一个 do-while 自旋 - 没有竞争时,通常一次就成功;高并发下可能重试多次,但线程始终在用户态运行,不触发上下文切换
- 这也是它比 synchronized 轻量的关键——省掉了挂起/唤醒开销
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










