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 小时前
【C语言】 函数基础与定义
c语言·开发语言·算法
编程彩机2 小时前
互联网大厂Java面试:从Java SE到大数据场景的技术深度解析
java·大数据·spring boot·面试·spark·java se·互联网大厂
笨蛋不要掉眼泪2 小时前
Spring Boot集成LangChain4j:与大模型对话的极速入门
java·人工智能·后端·spring·langchain
梵刹古音2 小时前
【C语言】 结构化编程与选择结构
c语言·开发语言·嵌入式
Yvonne爱编码3 小时前
JAVA数据结构 DAY3-List接口
java·开发语言·windows·python
一方_self3 小时前
了解和使用python的click命令行cli工具
开发语言·python
南宫码农3 小时前
我的电视 - Android原生电视直播软件 完整使用教程
android·开发语言·windows·电视盒子
CoderCodingNo3 小时前
【GESP】C++四级/五级练习题 luogu-P1223 排队接水
开发语言·c++·算法
像少年啦飞驰点、3 小时前
零基础入门 Spring Boot:从“Hello World”到可上线微服务的完整学习指南
java·spring boot·微服务·编程入门·后端开发