Java并发中的CAS机制:原理、应用与挑战(通俗易懂版)
上一期文章内容:Java并发中的乐观锁与悲观锁,
本期文章我们来讲一下Java并发中的CAS机制
一、从银行账户案例理解CAS

CAS 是一种乐观锁机制,用于在不使用锁的情况下实现多线程对共享资源的并发访问。
它包含三个操作数:内存位置(V)、预期原值(A)和新值(B)。
当且仅当内存位置 V 的值等于预期原值 A 时,才将内存位置 V 的值更新为新值 B;
否则,不做任何操作。整个 CAS 操作是原子性的,由 CPU 硬件指令直接支持。
想象这样一个场景:你和朋友同时查看一个银行账户余额为100元,你们都尝试转账。传统做法是银行用"锁"机制,只允许一人操作。而CAS(Compare-And-Swap比较交换)采用更聪明的策略:
你查询当前余额:100元(旧值)
系统记录此刻的版本号为V1
当你提交转账时,系统会检查:
当前余额是否仍是100元?
版本号是否还是V1?
只有当两者都满足时,转账才会成功,并更新版本号为V2
这种无锁机制就像超市自助结账——不需要收银员(锁),顾客(线程)自己完成操作,系统通过版本检查保证安全。
二、Java底层实现揭秘
2.1 神秘的Unsafe类
Java通过sun.misc.Unsafe类实现CAS,这个类就像Java世界的"瑞士军刀",为什么会这么说呢?
因为 sun.misc.Unsafe 类功能强大并且多样,提供了直接操作内存、基于CAS的操作方法、线程调度相关方法等的能力,但是我们在使用时需要持谨慎态度,因为会涉及安全、可移植、代码维护等问题!
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),整个过程就像:
获取当前值
计算新值
调用CPU指令进行原子比较交换
2.2 AtomicInteger实现解析
以AtomicInteger为例,看Java如何包装CAS:
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
线程A读取100(版本V1)
线程B完成两次修改(V1→V2→V3)
线程A的CAS检查值仍是100,但版本已变化
解决方案: 使用带版本号的AtomicStampedReference
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空转。优化策略:
-
自适应自旋:JVM动态调整自旋次数
-
pause指令:插入CPU提示指令降低功耗
// x86架构实现示例 __asm__ volatile ("pause"); -
退避策略:随机等待后再重试
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性能优势明显
极端竞争:可能需要退化为锁机制
相关文章:
Java并发中的CAS机制:原理、应用与挑战(通俗易懂版)
上一期文章内容:Java并发中的乐观锁与悲观锁, 本期文章我们来讲一下Java并发中的CAS机制 一、从银行账户案例理解CAS CAS 是一种乐观锁机制,用于在不使用锁的情况下实现多线程对共享资源的并发访问。 它包含三个操作数:内存位置&a…...
腾讯发布混元-3D 2.0: 首个开源高质3D-DiT生成大模型
在之前的文章中已经和大家介绍过腾讯HunYuan-3D 1.0,感兴趣的小伙伴可以点击下面链接阅读~ HunYuan-3D 是首个开源高质3D-DiT生成大模型,几何与纹理解藕生成,一键将创意具象化。 2.0模型架构图及介绍 2.0模型将几何和纹理生成解耦࿰…...
【机器学习】线性回归与一元线性回归
线性回归与一元线性回归 V1.1线性回归问题线性方程的最优解一元线性回归一元线性回归的方程一元线性回归距离衡量方法一元线性回归的最优化求解一元线性回归的最小二乘法解法 V1.1 线性回归问题 线性回归问题就是找一条线或超平面,并使用线或超平面来描述数据分布…...
哈希表-两个数的交集
代码随想录-刷题笔记 349. 两个数组的交集 - 力扣(LeetCode) 内容: 集合的使用 , 重复的数剔除掉,剩下的即为交集,最后加入数组即可。 class Solution {public int[] intersection(int[] nums1, int[] nums2) {Set<Integer…...
望远镜成像系统--科学评价光学镜头
望远镜是一种利用透镜或反射镜以及其他光学器件观测遥远物体的光学仪器。其原理是通过透镜的折射或反射镜的反射,将光线聚焦成像,再经过一个放大目镜进行观察。日常生活中的光学望远镜又称“天文望远镜”。1608年,荷兰的一位眼镜商汉斯利伯希…...
服务器延迟给视频网站造成的影响
在数字化时代中,网络视频已经成为人们日常娱乐和获取信息的重要平台,网络视频的流畅性会影响着用户的体验度,那么,当服务器出现延迟会对视频网站造成哪些影响呢?本文就来共同了解一下吧! 当所使用的服务器由…...
C++算法竞赛基础语法-9
快速排序是一种高效的排序算法,由C. A. R. Hoare在1960年提出,基本思想是分治法(Divide and Conquer)策略,通过递归将一个大问题分解为若干个较小的子问题,然后合并这些子问题的解来解决原始问题 快速排序…...
国产编辑器EverEdit - 极简追梦人的福音:迷你查找
1 迷你查找 1.1 应用场景 某些场景下,用户不希望调出复杂的查找对话框,此时可以使用迷你查找窗口。 1.2 使用方法 选择主菜单查找 -> 迷你查找,或使用快捷键Ctrl Alt F,会在右上角弹出迷你查找窗口,如下图所示…...
Flutter 异步编程利器:Future 与 Stream 深度解析
目录 一、Future:处理单次异步操作 1. 概念解读 2. 使用场景 3. 基本用法 3.1 创建 Future 3.2 使用 then 消费 Future 3.3 特性 二、Stream:处理连续异步事件流 1. 概念解读 2. 使用场景 3. 基本用法 3.1 创建 Stream 3.2 监听 Stream 3.…...
数据结构 day05
数据结构 day05 5. 队列5.3. 链式队列5.3.1. 特征5.3.2. 代码实现 6. 双向链表6.1. 特性6.2. 代码实现 5. 队列 5.3. 链式队列 5.3.1. 特征 逻辑结构:线性结构 存储结构:链式存储 操作:创建、入列、出列、判空、清空 5.3.2. 代码实现 头文…...
股票数据接口API实例代码python、JAVA等多种语言演示免费获取实时数据、历史数据、CDMA、KDJ等指标数据配有API说明文档
本文中所有接口均可直接在浏览器打开获取数据,为了便于大家验证有效性,已经做好了超链接,直接点击即可! 沪深两市股票列表 API接口链接(可点击验证):https://api.mairui.club/hslt/list/b…...
【Map vs Set】:Java数据存储的“双子星”对决
个人主页:♡喜欢做梦 欢迎 👍点赞 ➕关注 ❤️收藏 💬评论 目录 🍰一、搜索 🍮1.概念 🍮2.模型 🍰二、Map 🍨1.什么是Map? 🍨2.Map的实例化 &…...
ollama+langchain+deepseek本机跑通大模型
一、部署deepseek Ollama,这是是一个开源的大语言模型平台,它允许用户在本地环境中运行、创建和共享大型语言模型。Ollama提供了丰富的功能和特性,使得用户可以在自己的计算机上轻松地部署和运行大型语言模型。官网:https://ollam…...
03【FreeRTO队列-如何获取任务信息与队列的动静态创建】
一.利用 vTaskList()以及 vTaskGetRunTimeStats()来获取任务的信息 1.现象与开启启用宏 freeRTOSConfig.h //必须启用 #define configUSE_TRACE_FACILITY 1 #define configGENERATE_RUN_TIME_STATS 1 #define configUSE_STATS_FORMATTING_FUNCTIONS…...
vue-plugin-hiprint (vue2
页面效果 <template><div><div class="d-flex flex-column mt5"><div class="d-flex flex-row " style="margin-bottom: 10px;justify-content: center;"><!-- 纸张大小 A3、A4 等 --><div class="paper…...
【后端面试总结】什么是堆,什么是栈
堆与栈:计算机科学中的两大内存管理利器 在计算机科学中,内存管理是软件开发的核心组成部分之一。其中,堆(Heap)和栈(Stack)是两种最基本的内存分配方式,它们各自有着独特的特性和应…...
第39周:猫狗识别 2(Tensorflow实战第九周)
目录 前言 一、前期工作 1.1 设置GPU 1.2 导入数据 输出 二、数据预处理 2.1 加载数据 2.2 再次检查数据 2.3 配置数据集 2.4 可视化数据 三、构建VGG-16网络 3.1 VGG-16网络介绍 3.2 搭建VGG-16模型 四、编译 五、训练模型 5.1 上次程序的主要Bug 5.2 修改版…...
力扣--239.滑动窗口最大值
问题 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1: 输入:nums [1,3,-1,-3,5,3,6,7], …...
傅里叶变换推导
基本模型 假设在二维直角坐标系中,可以用相互垂直的基向量和表示: 假设: 假设在上的投影为,那么: 所以: 用公式表达: 但是在实际中,基向量和不一定长度都是1,重新推导一…...
扣子工作流中禁止同类别的图像流节点,不能超过4个
一、问题1不能在一个工作流中超过4个图像的并行节点 1、现象 本来想着在扣子中一次生成多张图片。 然后问了扣子小助手 2、图像节点限制 扣子给了如下反馈 近期图像流上线了并发限额,具体规则如下: 针对对象:单用户维度,非 bot…...
Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误
HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误,它们的含义、原因和解决方法都有显著区别。以下是详细对比: 1. HTTP 406 (Not Acceptable) 含义: 客户端请求的内容类型与服务器支持的内容类型不匹…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险
C#入门系列【类的基本概念】:开启编程世界的奇妙冒险 嘿,各位编程小白探险家!欢迎来到 C# 的奇幻大陆!今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类!别害怕,跟着我,保准让你轻松搞…...
华为OD机试-最短木板长度-二分法(A卷,100分)
此题是一个最大化最小值的典型例题, 因为搜索范围是有界的,上界最大木板长度补充的全部木料长度,下界最小木板长度; 即left0,right10^6; 我们可以设置一个候选值x(mid),将木板的长度全部都补充到x,如果成功…...
LOOI机器人的技术实现解析:从手势识别到边缘检测
LOOI机器人作为一款创新的AI硬件产品,通过将智能手机转变为具有情感交互能力的桌面机器人,展示了前沿AI技术与传统硬件设计的完美结合。作为AI与玩具领域的专家,我将全面解析LOOI的技术实现架构,特别是其手势识别、物体识别和环境…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
数据结构:泰勒展开式:霍纳法则(Horner‘s Rule)
目录 🔍 若用递归计算每一项,会发生什么? Horners Rule(霍纳法则) 第一步:我们从最原始的泰勒公式出发 第二步:从形式上重新观察展开式 🌟 第三步:引出霍纳法则&…...
