Java并发中的CAS机制:原理、应用与挑战(通俗易懂版)

ops/2025/2/22 15:59:01/

上一期文章内容:Java并发中的乐观锁与悲观锁,

本期文章我们来讲一下Java并发中的CAS机制


一、从银行账户案例理解CAS

        CAS 是一种乐观锁机制,用于在不使用锁的情况下实现多线程对共享资源的并发访问

        它包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。

        当且仅当内存位置 V 的值等于预期原值 A 时,才将内存位置 V 的值更新为新值 B;

        否则,不做任何操作。整个 CAS 操作是原子性的,由 CPU 硬件指令直接支持。

        想象这样一个场景:你和朋友同时查看一个银行账户余额为100元,你们都尝试转账。传统做法是银行用"锁"机制,只允许一人操作。而CAS(Compare-And-Swap比较交换)采用更聪明的策略:

  1. 你查询当前余额:100元(旧值)

  2. 系统记录此刻的版本号为V1

  3. 当你提交转账时,系统会检查:

    • 当前余额是否仍是100元?

    • 版本号是否还是V1?

  4. 只有当两者都满足时,转账才会成功,并更新版本号为V2

这种无锁机制就像超市自助结账——不需要收银员(锁),顾客(线程)自己完成操作,系统通过版本检查保证安全。


二、Java底层实现揭秘

2.1 神秘的Unsafe类

Java通过sun.misc.Unsafe类实现CAS,这个类就像Java世界的"瑞士军刀",为什么会这么说呢?

因为 sun.misc.Unsafe 类功能强大并且多样,提供了直接操作内存、基于CAS的操作方法、线程调度相关方法等的能力,但是我们在使用时需要持谨慎态度,因为会涉及安全、可移植、代码维护等问题!

java">public final class Unsafe {// 对象类型CASpublic final native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);// int类型CASpublic final native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);// long类型CASpublic final native boolean compareAndSwapLong(Object obj, long offset, long expect, long update);
}

通过JNI调用本地代码,最终映射到CPU指令(如x86的CMPXCHG),整个过程就像:

  1. 获取当前值

  2. 计算新值

  3. 调用CPU指令进行原子比较交换

2.2 AtomicInteger实现解析

AtomicInteger为例,看Java如何包装CAS:

java">public class AtomicInteger {private volatile int value; // 保证可见性private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset; // 内存偏移量static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}public final boolean compareAndSet(int expect, int update) {return unsafe.compareAndSwapInt(this, valueOffset, expect, update);}
}

关键点说明:

  • volatile保证值变更的可见性

  • 内存偏移量定位字段位置

  • CAS失败时自动重试(自旋

三、CAS的三大挑战与应对

3.1 ABA问题:账户余额的"时空穿越"

假设账户余额变化:100 → 200 → 100

  1. 线程A读取100(版本V1)

  2. 线程B完成两次修改(V1→V2→V3)

  3. 线程A的CAS检查值仍是100,但版本已变化

解决方案: 使用带版本号的AtomicStampedReference

java">AtomicStampedReference<Integer> account = new AtomicStampedReference<>(100, 0);// 存款操作
int[] stampHolder = new int[1];
int current = account.get(stampHolder);
if(account.compareAndSet(current, current+50, stampHolder[0], stampHolder[0]+1)) {System.out.println("存款成功");
}

3.2 自旋开销:CPU的"空转危机"

当多个线程激烈竞争时,CAS可能导致CPU空转。优化策略:

  1. 自适应自旋:JVM动态调整自旋次数

  2. pause指令:插入CPU提示指令降低功耗

    // x86架构实现示例
    __asm__ volatile ("pause");
  3. 退避策略:随机等待后再重试

3.3 多变量原子性:关联操作的困局

需要保证多个变量的原子更新时:

方案一:对象包装

class Account {int balance;int version;
}AtomicReference<Account> atomicAccount = new AtomicReference<>();

方案二:锁机制

synchronized(lock) {account.balance -= amount;account.version++;
}

四、CAS应用场景分析

场景适用性示例
计数器★★★★★AtomicInteger
状态标志★★★★★AtomicBoolean
对象引用更新★★★★☆AtomicReference
复杂数据结构★★☆☆☆ConcurrentHashMap内部实现
事务性操作★☆☆☆☆需要结合其他机制

五、性能对比:CAS vs 锁
 

通过JMH基准测试(ops/ms):

线程数    CAS    同步锁      ReentrantLock
1  15234    14567        14230
4  12345    2345        4566
8  9876    1023        2348

结论:

        低竞争场景:性能相近

        高并发场景:CAS性能优势明显

        极端竞争:可能需要退化为锁机制


http://www.ppmy.cn/ops/158531.html

相关文章

期权帮|股指期货保证金制度解析!

锦鲤三三每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 股指期货保证金制度解析&#xff01; 股指期货保证金制度是股指期货交易中的重要制度之一&#xff0c;它降低了投资者的持仓成本、提高了资金利用效率&#xff0c;但同时也带来…

Node.js 调用 DeepSeek API 完整指南

简介 本文将介绍如何使用 Node.js 调用 DeepSeek API&#xff0c;实现流式对话并保存对话记录。Node.js 版本使用现代异步编程方式实现&#xff0c;支持流式处理和错误处理。 1. 环境准备 1.1 系统要求 Node.js 14.0 或更高版本npm 包管理器 1.2 项目结构 deepseek-proje…

RocketMQ及和Kafka的区别

目录 1 从场景入手2 RocketMQ是什么&#xff1f;3 RocketMQ及和Kafka的区别3.1 在架构上做了减法3.1.1 简化协调节点3.1.2 简化分区3.1.3 底层存储3.1.3.1 Kafka底层存储3.1.3.1 RocketMQ底层存储 3.1.4 简化备份模型3.1.4.1 Kafka备份模型3.1.4.2 RocketMQ备份模型 3.1.5 Rock…

HCIA项目实践---ACL访问控制列表相关知识和配置过程

十 ACL访问控制列表 1 策略的概念 在网络连通之后&#xff0c; 把所有为了追求控制而实现的技术都叫策略 2 访问控制 在路由器流量流入或者流出的接口上&#xff0c;匹配流量&#xff0c;执行相应的动作。&#xff08;流量流入或者流出的接口并不是一个固定的概念而是一个相对的…

PMP冲刺每日一题(8)

试题1 您已经被委派为某项目的项目经理&#xff0c;权职范围明确界定&#xff0c;限于产品总装线的设计及建设阶段。客户组的一位成员向项目部门主管要求在项目安装阶段完成一项小工作。项目部门主管请客户询问项目经理。对这一请求的答复应包括∶ A、经修订的资源计划 B、经项…

javafx HTMLEditor自定义字体

javafx HTMLEditor原有的字体选择有很多&#xff0c;选择的时候很难定位为常用的&#xff0c;所以需要自定义HTMLEditor的字体选择。 可以使用lookupAll查找到字体选择的ComboBox int i 0;limitedFonts FXCollections.observableArrayList("SimSun", "SimHei…

flutter isolate到底是啥

在 Flutter 中&#xff0c;Isolate 是一种实现多线程编程的机制&#xff0c;下面从概念、工作原理、使用场景、使用示例几个方面详细介绍&#xff1a; 概念 在 Dart 语言&#xff08;Flutter 开发使用的编程语言&#xff09;里&#xff0c;每个 Dart 程序至少运行在一个 Isol…

什么关系型数据库和非关系型数据库

一、关系型数据库 1. 定义 关系型数据库是基于关系模型的数据库&#xff0c;用二维表结构来存储数据&#xff0c;表与表之间可以通过关系&#xff08;如主键-外键关系&#xff09;相互关联。 2. 特点 2.1 数据结构化 数据按照预定义的表结构进行存储&#xff0c;每个表有固…