尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Java并发编程原理精讲:CAS与Atomic原子操作详解

Java并发编程原理精讲:CAS与Atomic原子操作详解
📅 发布时间:2026/6/19 4:28:17

一、CAS无锁并发原理全解

1.1 CAS介绍

1.1.1 CAS全称与定义

CAS全称Compare And Swap,比较并交换,是非阻塞同步的实现原理,是CPU硬件级别提供的无锁原子指令,属于乐观锁核心实现原理,JDK底层依托Unsafe类封装调用,实现多线程下变量无锁安全修改。

CAS三大核心操作参数:内存值V、预期旧值E、更新新值N

1.1.2 CAS核心核心定论

  1. CAS是乐观锁、synchronized是悲观锁,二者并发设计理念完全对立

  2. CAS硬件级原子指令,执行过程不可被线程中断,天然保证操作原子性

  3. JDK5之后所有Atomic原子类、自旋锁、ConcurrentHashMap底层全部依托CAS实现

1.2 CAS完整执行过程

1.2.1 标准执行逻辑

  1. 线程从主内存读取共享变量,获取当前内存值V

  2. 线程传入预期修改旧值E、目标修改新值N

  3. CPU原子比对:内存值V == 预期旧值E?

    1. 相等:说明变量未被其他线程修改,直接将内存值V更新为新值NB,返回修改成功

    2. 不相等:说明变量已被其他线程篡改,放弃本次修改,返回修改失败

  4. 修改失败后,线程自选重试,直至修改成功

具体流程图如下:

1.2.2 通俗案例

银行卡余额:当前余额100(V),我预期余额100(E),想要充值改为200(N);查询余额没变则修改,余额变动则放弃充值,重新读取余额重试。

1.3 CAS代码使用方式

Java无法直接调用CPU指令,必须通过sun.misc.Unsafe底层类调用native本地方法执行CAS操作,分为原生Unsafe调用、原子类封装调用两种方式。

1.3.1 方式1:原生Unsafe手动CAS实操

public class CasUnsafeDemo { // 共享变量 private volatile int num = 0; // 获取Unsafe底层对象 private static final Unsafe UNSAFE; // 变量内存偏移量 private static long offset; static { try { UNSAFE = Unsafe.getUnsafe(); // 获取num变量内存地址偏移量 offset = UNSAFE.objectFieldOffset(CasUnsafeDemo.class.getDeclaredField("num")); } catch (Exception e) { throw new RuntimeException(e); } } public static void main(String[] args) { CasUnsafeDemo demo = new CasUnsafeDemo(); // CAS参数:对象、偏移量、预期旧值、更新新值 boolean success = UNSAFE.compareAndSwapInt(demo, offset, 0, 100); System.out.println("CAS修改结果:"+success); // true } }

以compareAndSwapInt 为例,Unsafe 的compareAndSwapInt 方法接收4 个参数,分别是:对象实例、内存偏移量、字段期望值、字段新值。该方法会针对指定对象实例中的相应偏移量的字段执行CAS 操作。

1.3.2 方式2:AtomicInteger封装简化使用(生产常用)

// 内置封装CAS,无需手动操作Unsafe偏移量 AtomicInteger atomicInteger = new AtomicInteger(0); // 比较并交换:预期0,更新为200 boolean casResult = atomicInteger.compareAndSet(0,200);

1.4 CAS线上生产应用场景

  1. JDK并发容器底层:ConcurrentHashMap、CopyOnWriteArrayList读写CAS管控并发

  2. 原子计数场景:接口访问量、秒杀库存、全局序列号、线程计数器

  3. 自旋锁自定义实现:基于CAS实现轻量自旋锁,替代短时synchronized锁

  4. 乐观锁业务落地:数据库版本号乐观锁、分布式本地无锁扣减

  5. 线程池状态修改:线程池运行/关闭状态,CAS原子修改状态标识

  6. 自定义并发工具:实现限流计数器、令牌桶限流核心逻辑

1.5 CAS底层源码深度分析(JDK8 HotSpot)

1.5.1 Java层Unsafe入口源码

// native本地方法,直接对接操作系统+CPU指令 public final native boolean compareAndSwapInt(Object o, long offset,int expected,int x);

1.5.2 JNI本地C++源码流程

  1. Unsafe调用Jni接口,跳转hotspot源码unsafe.cpp

  2. 封装入参,调用Atomic::cmpxchg原子汇编方法

  3. 追加lock总线锁指令:锁定CPU总线,保证多CPU核心下指令原子性

  4. 执行CPU汇编指令:cmpxchg 完成硬件级比较交换

  5. 释放总线锁,返回布尔修改结果至Java层

1.5.3 核心底层要点

  • volatile配合CAS:volatile保证变量内存可见性,CAS保证修改原子性,二者缺一不可

  • lock指令:锁定总线,禁止其他CPU同时修改共享变量,解决多核并发竞争

1.6 CAS核心优势(对比synchronized悲观锁)

  • 无线程阻塞:CAS自旋重试,不会进入内核态阻塞线程,无线程上下文切换开销

  • 性能极高:短时竞争场景,CAS吞吐量远超重量级synchronized锁

  • 开销极低:用户态完成操作,无需内核态切换,系统资源占用少

  • 粒度灵活:仅针对单个共享变量修改,锁粒度远小于对象锁、类锁

  • 代码轻量化:原子类封装后编码简单,无需手动加锁解锁

1.7 CAS原生四大缺陷

  • 自旋开销大:高并发竞争激烈时,CAS无限重试自旋,持续占用CPU资源,CPU飙高

  • 只能保证单个变量原子性:无法实现多个共享变量联合原子修改,仅支持单变量操作

  • 无法拦截业务逻辑:仅能比对变量值,无法管控业务代码流程

  • 存在ABA并发问题:变量值轮回篡改,CAS无法感知中间修改流程,判定修改无误,引发业务bug

1.8 ABA问题完整闭环:定义、危害、解决方案

1.8.1 ABA问题标准定义

线程1读取内存值A,准备CAS修改;期间线程2将值A改为B,再改回A;线程1比对内存值依旧为A,判定变量未修改,直接执行修改,忽略变量中间篡改流程,即为ABA问题。

1.8.2 ABA业务危害

资金转账、库存扣减、链表节点修改、分布式余额场景,会出现数据错乱、节点丢失、资金扣减异常,高资产业务致命bug。

1.8.3 ABA三大解决方案(优先级排序)

  1. 版本戳机制(最优方案):新增版本号Stamp,不仅比对变量值,同时比对版本号,每修改一次版本号自增,值相同版本不同则判定已修改,JDK自带AtomicStampedReference实现

  2. 时间戳标记:绑定变量最后修改时间,双重校验值+时间戳

  3. 业务全局唯一标识:业务层增加流水ID,规避数值轮回复用

1.8.4 解决ABA代码示例

// 带版本戳原子引用,解决ABA AtomicStampedReference<Integer> stamped = new AtomicStampedReference<>(100,1); // 参数:预期值、新值、预期版本、新版本 stamped.compareAndSet(100,200,1,2);

二、Atomic原子操作类全解(JDK8专属差异化)

在并发编程中很容易出现并发安全的问题,有一个很简单的例子就是多线程更新变量i=1,比如多个
线程执行i++操作,就有可能获取不到正确的值,而这个问题,最常用的方法是通过Synchronized进行控制来达到线程安全的目的。但是由于synchronized是采用的是悲观锁策略,并不是特别高效的一种解决方案。实际上,在J.U.C下的atomic包提供了一系列的操作简单,性能高效,并能保证线程安全的类去更新基本类型变量,数组元素,引用类型以及更新对象中的字段类型。atomic包下的这些类都是采用的是乐观锁策略去原子更新数据,在java中则是使用CAS操作具体实现。

2.1 JDK8六大分类原子操作类、JDK7/JDK8差异对比

2.1.1 JDK8全套原子类分类

  1. 基本数据类型原子类:AtomicInteger、AtomicLong、AtomicBoolean

  2. 引用类型原子类:AtomicReference、AtomicStampedReference、AtomicMarkableReference

  3. 数组原子类:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

  4. 对象字段原子类:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

  5. 累加器原子类(JDK8新增)::DoubleAccumulator、DoubleAdder、LongAccumulator、
    LongAdder、Striped64

  6. 复合标记原子类:带版本/标记防ABA专属原子类

2.1.2 JDK7与JDK8原子类核心差异

对比维度

JDK7原子类

JDK8原子类

底层CAS策略

单值无限自旋CAS,所有线程竞争同一个变量

分段Cell数组分散竞争,多线程分片CAS

高并发性能

竞争激烈自旋耗时久,CPU占用极高

分散竞争,自旋次数大幅降低,性能提升5-10倍

新增类

无累加器工具类

新增LongAdder、Accumulator函数式累加类

内存布局

无缓存行填充,伪共享问题严重

@sun.misc.Contended缓存行填充,解决伪共享

2.2 全类型原子类实操示例代码(可直接运行)

2.2.1 基本类型原子类示例

// 整型原子类 AtomicInteger atomicInt = new AtomicInteger(0); atomicInt.getAndIncrement(); // i++ atomicInt.incrementAndGet(); // ++i atomicInt.addAndGet(5); // 累加指定值 atomicInt.compareAndSet(5,10); // CAS修改

2.2.2 引用类型防ABA原子类示例

// 带版本戳,彻底解决ABA User user1 = new User(1,"张三"); User user2 = new User(2,"李四"); // 初始值+初始版本号 AtomicStampedReference<User> atomicUser = new AtomicStampedReference<>(user1,1); // 校验值+版本,双重CAS atomicUser.compareAndSet(user1,user2,1,2);

2.2.3 数组原子类示例

// 数组下标元素原子修改,线程安全 AtomicIntegerArray intArray = new AtomicIntegerArray(new int[]{1,2,3}); // 修改下标0元素,预期1改为99 intArray.compareAndSet(0,1,99);

2.2.4 对象字段更新原子类示例

// 仅修改对象volatile字段,无需封装整个对象,节省内存 class Student{ public volatile int age; } // 指定类+字段原子更新 AtomicIntegerFieldUpdater<Student> updater = AtomicIntegerFieldUpdater.newUpdater(Student.class,"age"); Student student = new Student(); updater.compareAndSet(student,0,18);

2.2.5 JDK8新增LongAdder分段累加示例

// 高并发计数首选,分段累加,性能碾压AtomicLong LongAdder longAdder = new LongAdder(); longAdder.increment(); longAdder.add(10); // 汇总所有分段数值,获取总数 long total = longAdder.sum();

2.3 Atomic原子操作类整体优缺点

2.3.1 通用优点

  • 底层CAS无锁,并发性能优于synchronized重量级锁

  • API封装完善,无需手动操作Unsafe、内存偏移量,开发便捷

  • 细分场景适配齐全:基础类型、数组、对象、防ABA全覆盖

  • JDK8优化分段CAS、缓存行填充,解决高并发自旋、伪共享痛点

  • 轻量无阻塞,适合短时高频变量修改场景

2.3.2 通用缺点

  • 基础原子类存在ABA问题,业务需额外引入版本戳原子类

  • 超高并发竞争下,依旧存在自旋空转、CPU占用升高问题

  • 仅支持变量原子修改,无法实现多行业务代码原子性

  • LongAdder只能做累加统计,无法精准CAS修改指定数值

2.4 Atomic原子类使用限制

  1. 多变量联动限制:无法同时原子修改多个无关共享变量,多变量必须使用锁机制

  2. 字段修饰限制:对象字段原子更新,目标字段必须被volatile修饰,否则无法保证可见性

  3. 访问权限限制:字段更新类,只能修改public/本类可访问字段,私有字段无法修改

  4. 功能场景限制:LongAdder仅适合计数,不适合精准条件修改业务

  5. 线程自旋限制:极端死锁竞争,CAS无限自旋,耗尽CPU核心资源

  6. 版本维护限制:防ABA原子类,业务需要手动维护版本号,编码复杂度提升

  7. 变量类型限制:只能是实例变量,只能是可修改变量

2.5 Atomic原子类线上生产分级应用场景

2.5.1 基础原子类场景(AtomicInteger/AtomicLong)

低并发接口计数、单点库存扣减、简单全局自增ID、状态标识修改

2.5.2 JDK8累加器场景(LongAdder)

超高并发流量统计、网关访问量、日志计数、监控指标累加、秒杀海量计数

2.5.3 防ABA引用原子类场景

资金账户余额修改、链表节点并发更新、分布式本地乐观锁、核心资产数据修改

2.5.4 对象字段原子更新场景

大量实体类状态修改,节省内存,无需封装整个对象为原子类,适配业务实体状态流转

2.5.5 数组原子类场景

并发批量下标数据统计、分片数据计数、数组点位独立修改业务

相关新闻

  • 追番神器,比B站好用的动漫看番网站,免费无广!
  • 2026年最新无人智习室加盟避坑 到底值不值得做看完就明白
  • 钢铁侠装甲机器人 - 综合部署指南

最新新闻

  • 微前端赋能电力存量系统升级|Vue2渐进式迁移Vue3、双栈兼容架构、业务零停机方案、电网全场景落地实战、全套工程代码复现
  • 2026年6月遵义黄金回收实测六家店铺逐一解析 - 余生黄金回收
  • 在职教师成人教育渠道,哪个口碑好,如何选择? - mypinpai
  • 2026 年大模型求职难?看看码士集团面试突击班都讲了啥
  • 24AA024H/24LC024H EEPROM应用指南:低功耗设计、I2C驱动与数据可靠性
  • AI应用软件开发流程通

日新闻

  • 5分钟掌握Python进化算法:Geatpy高性能优化工具完全指南
  • Microchip 24AA044 EEPROM选型与应用全指南:从参数解析到实战编程
  • 华为的鸿蒙到底有多牛?为什么称作遥遥领先?

周新闻

  • 3步解锁iOS设备:applera1n激活锁绕过完全指南
  • 39 2026 人工智能证书终极盘点,普通人选 AI 证书可以从这些方向入手
  • Redis 暴露公网有多危险?从端口检查到补救步骤

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号