Java 并发编程之 CAS 与 Atomic 原子操作类

一、CAS 核心原理

1. 定义与核心概念

  • CAS(Compare And Swap):比较与交换,是 CPU 硬件层面的原子指令,用于实现无锁同步。
  • 核心参数:内存值 V、预期值 E、新值 N。
  • 执行逻辑:当且仅当内存值 V == 预期值 E 时,将内存值更新为 N;无论是否更新,均返回原始内存值 V,整个过程原子性由硬件保障。
  • 本质:无锁算法(非阻塞同步)、乐观锁的实现方式。

2. Java 中的 CAS 实现

  • 底层依赖sun.misc.Unsafe类的 native 方法,提供三种类型的 CAS 操作:
    • compareAndSwapObject:对象类型
    • compareAndSwapInt:int 类型
    • compareAndSwapLong:long 类型
  • Unsafe类风险:直接操作内存,类似 C 语言指针,使用不当会破坏 Java 安全性,需谨慎使用。

3. 底层源码分析(Hotspot 虚拟机)

复制代码
// unsafe.cpp核心逻辑
UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) {
    UnsafeWrapper("Unsafe_CompareAndSwapInt");
    oop p = JNIHandles::resolve(obj);
    jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
    // 核心CAS指令调用
    return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
}
UNSAFE_END
  • x86 架构实现 :通过cmpxchgl指令完成,多处理器环境下添加lock前缀保证内存屏障。
  • 执行流程
    1. 将预期值 E 存入 eax 寄存器
    2. 比较 eax 与目标内存地址的值
    3. 相等则替换为新值 N,否则将内存值存入 eax
    4. 返回 eax 的值,判断 CAS 是否成功

4. CAS 的三大缺陷

缺陷 描述
自旋开销 高并发下 CAS 长时间失败,线程自旋会占用大量 CPU 资源
只能原子操作单个变量 无法直接实现多个共享变量的原子操作(需组合成对象间接实现)
ABA 问题 数据被修改为 B 后又恢复为 A,其他线程无法感知变化

5. ABA 问题解决方案

  • 问题演示:
  • 解决方案
    1. AtomicStampedReference :带版本号的原子引用,通过版本号递增保证唯一性
      • 构造参数:AtomicStampedReference(V initialRef, int initialStamp)
      • CAS 方法:compareAndSet(V expectedRef, V newRef, int expectedStamp, int newStamp)
    2. AtomicMarkableReference:简化版,仅通过 boolean 标记是否被修改(不关心修改次数)

二、Atomic 原子操作类体系

1. 核心分类与作用

类别 代表类 作用
基本类型原子类 AtomicInteger、AtomicLong、AtomicBoolean 原子更新基本数据类型
引用类型原子类 AtomicReference、AtomicStampedReference、AtomicMarkableReference 原子更新对象引用
数组类型原子类 AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 原子更新数组元素
对象属性原子修改器 AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater 原子更新对象的字段(无需修改原类)
原子累加器(JDK1.8+) LongAdder、DoubleAdder、LongAccumulator、DoubleAccumulator 高并发场景下高效累加,解决 AtomicLong 自旋瓶颈

2. 常用类详解

(1)基本类型原子类(以 AtomicInteger 为例)
  • 核心方法:
    • getAndIncrement():原子自增,返回旧值
    • incrementAndGet():原子自增,返回新值
    • addAndGet(int delta):原子累加 delta,返回新值
    • compareAndSet(int expect, int update):CAS 更新
  • 实现原理:基于 Unsafe 的 CAS 操作 + 自旋重试
(2)对象属性原子修改器(AtomicIntegerFieldUpdater)
  • 核心约束:
    1. 目标字段必须是volatile类型(保证可见性)
    2. 只能是实例变量(不能是 static)
    3. 不能是 final 变量(与修改语义冲突)
    4. 字段类型必须与修改器匹配(int 对应 AtomicIntegerFieldUpdater)
    5. 访问权限需一致(调用者能通过反射访问该字段)
(3)原子累加器(LongAdder)
  • 设计初衷:解决高并发下 AtomicLong 的自旋冲突问题

  • 核心原理 :分散热点,将累加值分散到Cell[]数组中

  • 核心结构

    • base:无竞争时的累加基数
    • Cell[]:竞争时的分散存储数组(大小为 2 的幂,与 CPU 核数相关)
    • cellsBusy:自旋锁,用于 Cell 数组的初始化和扩容
  • 与 AtomicLong 对比:| 特性 | AtomicLong | LongAdder ||------|------------|-----------|| 并发性能 | 低并发优秀,高并发自旋冲突严重 | 高并发下性能更优(分散热点) || 准确性 | 完全准确(每次操作原子性) | sum () 返回近似值(无锁累加) || 适用场景 | 低并发、需要精确计数 | 高并发、写多读少、允许近似计数 |

3. 典型应用场景

  • 并发计数器(如接口访问量统计)
  • 无锁数据结构(如 ConcurrentLinkedQueue)
  • 线程安全的状态管理(如状态标志位)
  • AQS 框架底层实现(ReentrantLock、CountDownLatch 等)
相关推荐
方安乐2 小时前
python之向量、向量和、向量点积
开发语言·python·numpy
代码AI弗森3 小时前
一文理清楚“算力申请 / 成本测算 / 并发评估”
java·服务器·数据库
Old Uncle Tom3 小时前
OpenClaw 记忆系统 -- 记忆预加载
java·数据结构·算法·agent
小小小米粒4 小时前
Collection单列集合、Map(Key - Value)双列集合,多继承实现。
java·开发语言·windows
摇滚侠4 小时前
expdp 查看帮助
java·数据库·oracle
czhc11400756634 小时前
C# 428 线程、异步
开发语言·c#
:1215 小时前
java基础
java·开发语言
SilentSamsara5 小时前
Python 环境搭建完整指南:从下载安装到运行第一个程序
开发语言·python
曹牧5 小时前
Spring:@RequestMapping注解,匹配的顺序与上下文无关
java·后端·spring
daixin88485 小时前
cursor无法正常使用gpt5.5等模型解决方案
java·redis·cursor