Java并发编程:深入解析原子操作类与CAS原理
一、原子操作类概述
Java并发包(java.util.concurrent.atomic)提供了一系列原子操作类,这些类通过无锁算法实现了线程安全的操作,相比传统的锁机制具有更高的性能。原子类基于CAS(Compare-And-Swap)指令实现,是现代并发编程的重要基础。
原子类主要分类:
- 基本类型:AtomicInteger、AtomicLong、AtomicBoolean
- 引用类型:AtomicReference、AtomicStampedReference、AtomicMarkableReference
- 数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
- 字段更新器:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
- 累加器:LongAdder、DoubleAdder(JDK8+)
- 累加器增强:LongAccumulator、DoubleAccumulator(JDK8+)
二、CAS原理深度解析
1. CAS操作语义
CAS是一种原子指令,包含三个操作数:
- 内存位置(V)
- 预期原值(A)
- 新值(B)
当且仅当V的值等于A时,处理器才会将V的值更新为B,否则不执行任何操作。无论哪种情况都会返回V的当前值。
2. Java中的CAS实现
Java通过Unsafe类提供CAS操作支持:
public final class Unsafe {public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
}
3. CAS的三大问题
-
ABA问题:值从A变为B又变回A,CAS会认为没变化
- 解决方案:使用AtomicStampedReference添加版本号
-
循环时间长开销大:CAS失败会自旋重试,消耗CPU
- 解决方案:JVM支持pause指令降低CPU消耗
-
只能保证一个变量的原子操作
- 解决方案:使用AtomicReference保证多个变量的原子性
三、核心原子类实现分析
1. AtomicInteger源码解析
public class AtomicInteger extends Number {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); }}private volatile int value;public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);}// Unsafe中的实现public final int getAndAddInt(Object o, long offset, int delta) {int v;do {v = getIntVolatile(o, offset);} while (!compareAndSwapInt(o, offset, v, v + delta));return v;}
}
2. LongAdder高性能原理
设计思想:分段CAS,减少竞争
- 内部维护一个Cell数组和base值
- 线程首先尝试更新base值
- 竞争激烈时,线程会分配到不同的Cell上进行更新
- 最终结果为base+∑Cell[i]
适用场景:高并发统计计数,不保证实时精确
四、原子类的典型应用
1. 计数器实现
public class Counter {private final AtomicLong count = new AtomicLong(0);public void increment() {count.incrementAndGet();}public long getCount() {return count.get();}
}
2. 单例模式优化
public class Singleton {private static final AtomicReference<Singleton> INSTANCE = new AtomicReference<>();private Singleton() {}public static Singleton getInstance() {for (;;) {Singleton instance = INSTANCE.get();if (instance != null) {return instance;}instance = new Singleton();if (INSTANCE.compareAndSet(null, instance)) {return instance;}}}
}
3. 状态标志管理
public class StatusManager {private final AtomicBoolean status = new AtomicBoolean(false);public void enable() {status.set(true);}public boolean tryDisable() {return status.compareAndSet(true, false);}
}
五、原子类性能优化
1. 伪共享(False Sharing)问题
问题描述:多个线程修改同一缓存行的不同变量,导致性能下降
解决方案:
- JDK8使用@Contended注解自动填充(需开启JVM参数)
- 手动填充(对于非JDK8或特定场景)
public class PaddedAtomicLong extends AtomicLong {public volatile long p1, p2, p3, p4, p5, p6 = 7L; // 填充public PaddedAtomicLong(long initialValue) {super(initialValue);}
}
2. 计数器选型建议
| 场景 | 推荐类 | 原因 |
|---|---|---|
| 低竞争环境 | AtomicLong | 实现简单,开销小 |
| 高并发写入 | LongAdder | 分段减少竞争,吞吐量高 |
| 需要复杂累加操作 | LongAccumulator | 支持自定义累加函数 |
六、原子类与锁的性能对比
测试场景:100个线程,每个线程递增计数器100,000次
| 实现方式 | 耗时(ms) | 特点 |
|---|---|---|
| synchronized | 420 | 稳定但性能一般 |
| ReentrantLock | 380 | 略优于synchronized |
| AtomicInteger | 120 | 无锁,性能最好 |
| LongAdder | 85 | 高并发下性能最优 |
结论:在适合的场景下,原子类性能显著优于锁机制
七、原子类最佳实践
- 优先使用JDK提供的原子类:避免重复造轮子
- 理解内存语义:原子类保证可见性,但不保证操作的原子组合
- 注意ABA问题:必要时使用带版本号的原子引用
- 高并发计数使用LongAdder:比AtomicLong性能更好
- 避免过度使用:不是所有场景都需要原子类
八、常见问题与解决方案
1. 原子类能完全替代锁吗?
答案:不能。原子类适合简单原子操作,复杂同步仍需锁机制
2. 为什么AtomicInteger比synchronized快?
原因:
- 无上下文切换开销
- 硬件级CAS指令比JVM锁更轻量
- 非阻塞算法减少线程等待
3. 如何选择AtomicReference和AtomicStampedReference?
建议:
- 不关心ABA问题:使用AtomicReference
- 需要解决ABA问题:使用AtomicStampedReference
九、总结
Java原子操作类是基于CAS实现的高性能线程安全工具,理解其原理和适用场景对于编写高效并发程序至关重要。在实际开发中,应根据具体场景选择合适的原子类,并注意其内存语义和潜在问题。掌握原子类的使用技巧,能够在保证线程安全的同时获得接近于无锁的性能,是Java并发编程的高级技能之一。
相关文章:
Java并发编程:深入解析原子操作类与CAS原理
一、原子操作类概述 Java并发包(java.util.concurrent.atomic)提供了一系列原子操作类,这些类通过无锁算法实现了线程安全的操作,相比传统的锁机制具有更高的性能。原子类基于CAS(Compare-And-Swap)指令实现,是现代并发编程的重要基础。 原…...
新一代AI低代码MES,助力企业数字化升级
随着DeepSeek低成本AI模型的火热,对于传统的MES而言,在这场AI的盛宴中,该如何去调整产品的定位,让MES更符合工业企业的需求呢? 工业互联网、AI、数字孪生等技术加速与MES融合,实现生产全流程的实时监控与智…...
位运算与实战场景分析-Java代码版
一、为什么每个程序员都要掌握位运算? 在电商秒杀系统中,位运算可以快速判断库存状态;在权限管理系统里,位运算能用极小的空间存储复杂权限配置;在算法竞赛中,位运算更是高频出现的性能优化利器。这项看似…...
面试之《前端信息加密》
前端代码是直接暴漏给用户的,请求的接口也可以通过控制台network看到参数,这是不够安全的,如果遇到坏人想要破坏,可以直接修改参数,或者频繁访问导致系统崩溃,或数据毁坏。 所以信息加密在某些场合就变得非…...
CentOS 系统磁盘扩容并挂载到根目录(/)的详细步骤
在使用 CentOS 系统时,经常会遇到需要扩展磁盘空间的情况。例如,当虚拟机的磁盘空间不足时,可以通过增加磁盘容量并将其挂载到根目录(/)来解决。以下是一个完整的操作流程,详细介绍了如何将新增的 10G 磁盘…...
HTML应用指南:利用GET请求获取全国汉堡王门店位置信息
在当今快节奏的都市生活中,餐饮品牌的门店布局不仅反映了其市场策略,更折射出消费者对便捷、品质和品牌认同的追求。汉堡王(Burger King)作为全球知名的西式快餐品牌之一,在中国市场同样占据重要地位。自进入中国市场以…...
浅入浅出 GRPO in DeepSeekMath
GRPO in DeepSeekMath GRPO 通过在生成组内进行比较来直接评估模型生成的响应,以优化策略模型,而不是训练单独的价值模型,这种方法显著降低了计算成本。GRPO 可以应用于任何可以确定响应正确性的可验证任务。例如,在数学推理中&a…...
计算机网络起源
互联网的起源和发展是一个充满创新、突破和变革的历程,从20世纪60年代到1989年,这段时期为互联网的诞生和普及奠定了坚实的基础。让我们详细回顾这一段激动人心的历史。 计算机的发展与ARPANET的建立(20世纪60年代) 互联网的诞生…...
HTML 嵌入标签对比:小众(<embed>、<object>) 与 <iframe> 的优缺点及使用场景和方式
需求背景 在网页开发中,嵌入外部资源预览(如视频、PDF、地图或其他网页)是常见的需求。HTML 提供了多种标签来实现这一功能,其中 <embed>、<object> 和 <iframe> 是最常用的三种。本文将对比它们的优缺点&…...
[python] 作用域
Python中查找变量的顺序遵循LEGB规则(Local->Enclosing->Global->Built-in)。Python中的if/elif/else、for/while等代码块不会创建新的作用域,只有def、class、lambda才会改变作用域。这和C中不同,C中在{}代码块中创建的变量离开这个代码块后就…...
AICon 2024年全球人工智能与大模型开发与应用大会(脱敏)PPT汇总(36份).zip
AICon 2024年全球人工智能与大模型开发与应用大会(脱敏)PPT汇总(36份).zip 1、面向开放域的大模型智能体.pdf 2、企业一站式 AI 智能体构建平台演进实践.pdf 3、PPIO 模型平台出海实战,跨地域业务扩展中的技术优化之道…...
51电子表
设计要求: 基本任务: 用单片机和数码管设计可调式电子钟,采用24小时制计时方式,要求能够稳定准确计时,并能调整时间。发光二极管每秒亮灭一次。电子钟显示格式为:时、分、秒各两位,中间有分隔…...
9-函数的定义及用法
一.前言 C 语⾔强调模块化编程,这⾥所说的模块就是函数,即把每⼀个独⽴的功能均抽象为⼀个函数来实现。从⼀定意义上讲,C 语⾔就是由⼀系列函数串组成的。 我们之前把所有代码都写在 main 函数中,这样虽然程序的功能正常实现&…...
高清视频会议系统BeeWorks Meet,支持私有化部署
在数字化办公时代,视频会议已成为企业协作的关键工具。然而,随着信息安全意识的不断提高,传统的公有云视频会议软件已难以满足企业对数据安全和隐私保护的严格要求。BeeWorks Meet凭借其独特的私有化部署模式、强大的功能集成以及对国产化的适…...
用HTML和CSS绘制佩奇:我不是佩奇
在这篇博客中,我将解析一个完全使用HTML和CSS绘制的佩奇(Pig)形象。这个项目展示了CSS的强大能力,仅用样式就能创造出复杂的图形,而不需要任何图片或JavaScript。 项目概述 这个名为"我不是佩奇"的项目是一个纯CSS绘制的卡通猪形象…...
彩讯携Rich AICloud与一体机智算解决方案亮相中国移动云智算大会
2025年4月10日,2025中国移动云智算大会在苏州盛大开幕,本次大会以“由云向智 共绘算网新生态”为主题,与会嘉宾围绕算力展开重点探讨。 大会现场特设区域展出各参会单位的最新算力成果,作为中国移动重要合作伙伴,彩讯…...
BERT - 直接调用transformers.BertModel, BertTokenizerAPI不进行任何微调
本节代码将使用 transformers 库加载预训练的BERT模型和分词器(Tokenizer),并处理文本输入。 1. 加载预训练模型和分词器 from transformers import BertTokenizer, BertModelmodel_path "/Users/azen/Desktop/llm/models/bert-base-…...
安卓开发提示Android Gradle plugin错误
The project is using an incompatible version (AGP 8.9.1) of the Android Gradle plugin. Latest supported version is AGP 8.8.0-alpha05 See Android Studio & AGP compatibility options. 改模块级 build.gradle(如果有独立配置):…...
声学测温度原理解释
已知声速,就可以得到温度。 不同温度下的胜诉不同。 25度的声速大约346m/s 绝对温度-273度 不同温度下的声速。 FPGA 通过测距雷达测温度,固定测量距离,或者可以测出当前距离。已知距离,然后雷达发出声波到接收到回波的时间&a…...
Cuto壁纸 2.6.9 | 解锁所有高清精选壁纸,无广告干扰
Cuto壁纸 App 提供丰富多样的壁纸选择,涵盖动物、风景、创意及游戏动漫等类型。支持分类查找与下载,用户可轻松将心仪壁纸设为手机背景,并享受软件内置的编辑功能调整尺寸。每天更新,确保用户总能找到新鲜、满意的壁纸。 大小&am…...
C语言 AI 通义灵码 VSCode插件安装与功能详解
在 C 语言开发领域,一款高效的编码助手能够显著提升开发效率和代码质量。 通义灵码,作为阿里云技术团队打造的智能编码助手,凭借其强大的功能,正逐渐成为 C 语言开发者的新宠。 本文将深入探讨通义灵码在 C 语言开发中的应用&am…...
二分查找5:852. 山脉数组的峰顶索引
链接:852. 山脉数组的峰顶索引 - 力扣(LeetCode) 题解: 事实证明,二分查找不局限于有序数组,非有序的数组也同样适用 二分查找主要思想在于二段性,即将数组分为两段。本体就可以将数组分为ar…...
1.2 测试设计阶段:打造高质量的测试用例
测试设计阶段:打造高质量的测试用例 摘要 本文详细介绍了软件测试流程中的测试设计阶段,包括测试用例设计、测试数据准备、测试环境搭建和测试方案设计等内容。通过本文,读者可以系统性地了解测试设计的方法和技巧,掌握如何高效…...
【模拟电路】稳压二极管/齐纳二极管
齐纳二极管也被称为稳压二极管,是一种特殊的二极管,其工作原理是利用PN结的反向击穿状态。在齐纳二极管中,当反向电压增加到一定程度,即达到齐纳二极管的击穿电压时,反向电流会急剧增加,但此时齐纳二极管的电压却基本保持不变。这种特性使得齐纳二极管可以作为稳压器或电…...
项目周期过长,如何拆分里程碑
应对项目周期过长,合理拆分里程碑需要做到:明确项目整体目标与阶段目标、合理进行任务细分与分组、设定阶段性里程碑节点、实施有效的进度跟踪与反馈机制、灵活进行里程碑调整。其中,明确项目整体目标与阶段目标尤为关键。这能够帮助团队在长…...
Java基础 - 泛型(常见用法)
文章目录 泛型类泛型方法泛型类派生子类示例 1:子类固定父类泛型类型(StringBox 继承自 Box<String>)示例 2:子类保留父类泛型类型(AdvancedBox<T> 继承自 Box<T>)示例 3:添加子类自己的…...
蓝桥杯刷题总结 + 应赛技巧
当各位小伙伴们看到这篇文章的时候想必蓝桥杯也快开赛了,那么本篇文章博主就来总结一下一些蓝桥杯的应赛技巧,那么依旧先来走个流程 那么接下来我们分成几个板块进行总结 首先是一些基本语法 编程语言的基本语法 首先是数组,在存数据的时候…...
希哈表的学习
#include <stdio.h> #include <stdlib.h> #include "uthash.h"typedef struct {int id; // 学号,作为keychar name[20]; // 姓名,作为valueUT_hash_handle hh; // 必须有这个字段 } Student;Student* studen…...
Qt之OpenGL使用Qt封装好的着色器和编译器
代码 #include "sunopengl.h"sunOpengl::sunOpengl(QWidget *parent) {}unsigned int VBO,VAO; float vertices[]{0.5f,0.5f,0.0f,0.5f,-0.5f,0.0f,-0.5f,-0.5f,0.0f,-0.5f,0.5f,0.0f };unsigned int indices[]{0,1,3,1,2,3, }; unsigned int EBO; sunOpengl::~sunO…...
备赛蓝桥杯-Python-考前突击
额,,离蓝桥杯开赛还有十个小时,最近因为考研复习节奏的问题,把蓝桥杯的优先级后置了,突然才想起来还有一个蓝桥杯呢。。 到目前为止python基本语法熟练了,再补充一些常用函数供明天考前再背背,算…...
