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 等)
相关推荐
2401_876907525 分钟前
Python机器学习实践指南
开发语言·python·机器学习
努力中的编程者24 分钟前
栈和队列(C语言底层实现环形队列)
c语言·开发语言
回到原点的码农40 分钟前
Spring Data JDBC 详解
java·数据库·spring
gf132111143 分钟前
python_查询并删除飞书多维表格中的记录
java·python·飞书
zb200641201 小时前
Spring Boot 实战:轻松实现文件上传与下载功能
java·数据库·spring boot
一勺菠萝丶1 小时前
Flowable + Spring 集成踩坑:流程结束监听器查询历史任务为空 & 获取不到审批意见
java·数据库·spring
jwn9991 小时前
Spring Boot 整合 Keycloak
java·spring boot·后端
宁波阿成1 小时前
OpenClaw 在 Ubuntu 22.04.5 LTS 上的安装与问题处理记录
java·linux·ubuntu·openclaw·龙虾
mldlds1 小时前
SpringBoot详解
java·spring boot·后端
kang_jin1 小时前
Spring Boot 自动配置
java·spring boot·后端