0

0

如何理解Java的原子性操作_CAS机制与Unsafe类底层初探

P粉602998670

P粉602998670

发布时间:2026-03-02 12:21:11

|

386人浏览过

|

来源于php中文网

原创

java中cas是原子的,但仅限单变量单次操作;映射为cmpxchg或ldxr/stxr等硬件指令,不可中断;多步逻辑、aba问题、自旋写法错误等均使其失去原子性保障。

如何理解java的原子性操作_cas机制与unsafe类底层初探

Java里CAS到底是不是“原子”的?

是,但仅限于单个变量的单次操作——Unsafe.compareAndSwapInt 这类调用在CPU指令层面映射为 cmpxchg(x86)或 ldxr/stxr(ARM),硬件保证其不可中断。可一旦你把它当“事务”用,比如先读A再CAS B,中间穿插了别的逻辑,那就不是原子的了。

常见错误现象:ABA问题、自旋空转导致CPU飙升、误以为 AtomicInteger.incrementAndGet() 能保护整个业务流程。

  • 使用场景:计数器、无锁队列节点链接、状态机切换(如从 INITRUNNING
  • Unsafe.compareAndSwapObjectcompareAndSwapInt 的参数顺序一致,但第三个参数是期望值,第四个是新值;传错会静默失败
  • 注意JDK 9+后 Unsafe 被限制,反射获取实例可能抛 IllegalAccessException,得用 jdk.internal.misc.Unsafe + JVM参数 --add-opens

为什么直接用Unsafe比AtomicInteger更危险?

因为 AtomicInteger 封装了内存屏障(如 getAndIncrement 底层插入 lock xadd)、volatile语义、以及对 Unsafe 的安全封装;而裸用 Unsafe 时,你得自己决定在哪加 Unsafe.storeFence()Unsafe.loadFence(),稍有遗漏就会出现可见性问题。

典型坑:Unsafe.putInt(obj, offset, 1) 不带任何屏障,其他线程可能永远看不到这个写入;而 AtomicInteger.set(1) 自动保证后续读能看见。

立即学习Java免费学习笔记(深入)”;

志设AI
志设AI

志设AI是一站式AI设计平台,集“AI生图 + 在线设计 + 素材交易 + 收益分成”于一体。

下载
  • 性能影响:裸 Unsafe 确实略快(少一层方法调用和检查),但差异在纳秒级,不值得用正确性换
  • 兼容性风险:不同JVM实现对 Unsafe 的支持细节有差异,比如某些嵌入式JVM压根没实现 compareAndSwapLong
  • 示例:想手动实现一个无锁栈,别直接用 Unsafe.compareAndSwapObject(head, offset, expect, update) 就完事——得确保 head 字段本身是 volatile 或用 Unsafe.getObjectVolatile 读取

“自旋等待”卡住不动?不是CAS没生效,是条件写错了

CAS失败只返回 false,它不阻塞也不重试;所谓“自旋”,是你自己写的 while (!cas(...)) { }。如果循环体里没更新期望值,就会无限失败。

错误现象:while (unsafe.compareAndSwapInt(obj, offset, expected, newValue)) ——这里 expected 没变,第二次就必然失败,死循环。

  • 正确做法:每次失败后,重新读取当前值作为新的 expected,例如 int cur = unsafe.getIntVolatile(obj, offset); while (!unsafe.compareAndSwapInt(obj, offset, cur, cur + 1)) { cur = unsafe.getIntVolatile(obj, offset); }
  • 注意 getIntVolatilegetInt 区别:后者不保证可见性,可能读到过期缓存值
  • 别在自旋里做耗时操作(如IO、锁、日志),否则不仅卡住自己,还拖垮整个CPU核

Unsafe的objectFieldOffset怎么算?别硬记偏移量

偏移量不是固定值,取决于JVM对象布局(OOP layout)、字段顺序、是否开启压缩指针(-XX:+UseCompressedOops)。手算容易错,也难移植。

常见错误:把 static final long OFFSET = 16 写死在代码里,换个JVM版本或GC策略就崩,报 IllegalArgumentException: field offset not aligned

  • 必须用 Unsafe.objectFieldOffset(Field) 动态获取,哪怕多一次反射调用
  • 字段必须是 public 或通过 setAccessible(true) 绕过访问控制,否则 getDeclaredField 找不到
  • 示例:Field f = MyCounter.class.getDeclaredField("value"); f.setAccessible(true); long offset = unsafe.objectFieldOffset(f);

真正麻烦的从来不是理解CAS原理,而是记住哪些地方要加屏障、哪些字段必须volatile、哪些offset不能硬编码——这些细节一漏,bug就藏在高并发偶现的角落里,很难复现。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

104

2023.09.25

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

910

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

596

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

294

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

210

2025.08.29

c++中volatile关键字的作用
c++中volatile关键字的作用

本专题整合了c++中volatile关键字的相关内容,阅读专题下面的文章了解更多详细内容。

75

2025.10.23

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

599

2023.08.10

Golang 测试体系与代码质量保障:工程级可靠性建设
Golang 测试体系与代码质量保障:工程级可靠性建设

Go语言测试体系与代码质量保障聚焦于构建工程级可靠性系统。本专题深入解析Go的测试工具链(如go test)、单元测试、集成测试及端到端测试实践,结合代码覆盖率分析、静态代码扫描(如go vet)和动态分析工具,建立全链路质量监控机制。通过自动化测试框架、持续集成(CI)流水线配置及代码审查规范,实现测试用例管理、缺陷追踪与质量门禁控制,确保代码健壮性与可维护性,为高可靠性工程系统提供质量保障。

45

2026.02.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 4万人学习

C# 教程
C# 教程

共94课时 | 10.5万人学习

Java 教程
Java 教程

共578课时 | 75.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号