0

0

Java中的线程安全之原子引用(AtomicReference)_管理复杂对象的原子性

P粉602998670

P粉602998670

发布时间:2026-02-28 10:21:11

|

902人浏览过

|

来源于php中文网

原创

atomicreference 仅保证引用读写原子性,不保护对象内部状态;适用引用替换场景,不适用于内部字段修改或复合操作;应优先用 compareandset() 而非 weakcompareandset();更新内部字段需循环 cas 构造新对象;相比 volatile,它提供原子更新能力而非仅可见性。

java中的线程安全之原子引用(atomicreference)_管理复杂对象的原子性

AtomicReference 为什么不能直接替换 synchronized?

它只保证引用本身的读写原子性,不保证对象内部状态的线程安全。比如用 AtomicReference<list>></list> 存一个 ArrayList,多个线程调用 list.add() 依然会出并发问题——因为 add() 是对象自己的方法,不在 AtomicReference 的保护范围内。

常见错误现象:NullPointerException 或数据丢失,表面看是 CAS 失败,实际是误以为“换了 AtomicReference 就万事大吉”。

  • 适用场景:需要无锁更新整个引用(比如切换配置对象、状态机切换、链表头节点)
  • 不适用场景:频繁修改对象内部字段、需要复合操作(如先 get 再 update 再 set)
  • 性能影响:比 synchronized 在低争用时更快,但高争用下 CAS 自旋可能浪费 CPU

compareAndSet() 和 weakCompareAndSet() 到底该用哪个?

weakCompareAndSet() 不保证内存顺序(JVM 可能重排),且不保证一定成功(即使条件满足也可能失败),仅用于极少数无锁算法的底层实现,比如 ConcurrentLinkedQueue 内部。日常业务代码一律用 compareAndSet()

容易踩的坑:weakCompareAndSet() 返回 false 不能直接当作“值已变”来处理,它可能是假失败;而 compareAndSet() 的语义明确:值相等就替换,返回布尔结果可直接用于控制流。

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

AI Room Planner
AI Room Planner

AI 室内设计工具,免费为您的房间提供上百种设计方案

下载
  • 参数差异:compareAndSet(expected, desired)expected 是当前期望值,必须严格等于内存中值才成功
  • 注意引用相等性:比较的是对象引用,不是内容。若想按内容比较,得自己封装逻辑(比如用 AtomicReference<atomicinteger></atomicinteger>
  • 兼容性:所有 JDK 版本都支持 compareAndSet()weakCompareAndSet() 在 JDK 9+ 才有更强语义(但依然慎用)

怎么安全地更新对象内部字段?

不能靠 AtomicReference 自动管理,得把“读-改-写”变成原子操作。最常用的是循环 CAS 模式(loop-CAS):

AtomicReference<User> ref = new AtomicReference<>(new User("a", 0));
User current;
User update;
do {
    current = ref.get();
    update = new User(current.name, current.age + 1); // 不改原对象
} while (!ref.compareAndSet(current, update));

关键点在于:每次构造新对象,避免共享可变状态;用 compareAndSet() 重试直到成功。

  • 如果对象字段多、构造开销大,考虑用 AtomicIntegerFieldUpdater 等字段级原子类替代
  • 禁止在循环里做耗时操作(如 IO、锁、复杂计算),否则会卡住其他线程的 CAS 尝试
  • 注意 ABA 问题:虽然引用没变,但中间被替换成别的对象又换回来。一般业务场景影响小,金融/底层结构需配合 AtomicStampedReference

和 volatile 引用比,AtomicReference 多了什么?

volatile 只保证可见性和禁止重排序,不提供原子更新能力。比如 volatile User user,你不能原子地执行 “如果 user != null 就 user.setName(‘x’)”,因为判断和赋值是两步。

AtomicReference 提供了 compareAndSet()getAndSet()updateAndGet() 这些带原子语义的操作,这才是它存在的核心价值。

  • 性能差异:两者读操作成本接近;AtomicReference 的写操作略重(涉及 CAS 指令),但换来的是确定的原子行为
  • 使用场景错位:volatile 适合“只读发布”或“单次写入后只读”,AtomicReference 适合需要反复更新引用的场景
  • 别混用:不要对同一个变量既加 volatile 又包进 AtomicReference,纯属冗余

真正难的从来不是记住 API,而是判断什么时候不该用它——比如对象本身不可变,那 volatile 就够了;比如操作本质是 I/O 密集型,锁反而更稳。原子引用不是银弹,它只解决引用层面的原子性这一个点。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
c语言中null和NULL的区别
c语言中null和NULL的区别

c语言中null和NULL的区别是:null是C语言中的一个宏定义,通常用来表示一个空指针,可以用于初始化指针变量,或者在条件语句中判断指针是否为空;NULL是C语言中的一个预定义常量,通常用来表示一个空值,用于表示一个空的指针、空的指针数组或者空的结构体指针。

248

2023.09.22

java中null的用法
java中null的用法

在Java中,null表示一个引用类型的变量不指向任何对象。可以将null赋值给任何引用类型的变量,包括类、接口、数组、字符串等。想了解更多null的相关内容,可以阅读本专题下面的文章。

927

2024.03.01

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

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

72

2025.10.23

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

722

2023.08.10

页面置换算法
页面置换算法

页面置换算法是操作系统中用来决定在内存中哪些页面应该被换出以便为新的页面提供空间的算法。本专题为大家提供页面置换算法的相关文章,大家可以免费体验。

480

2023.08.14

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

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

0

2026.02.28

Golang 工程化架构设计:可维护与可演进系统构建
Golang 工程化架构设计:可维护与可演进系统构建

Go语言工程化架构设计专注于构建高可维护性、可演进的企业级系统。本专题深入探讨Go项目的目录结构设计、模块划分、依赖管理等核心架构原则,涵盖微服务架构、领域驱动设计(DDD)在Go中的实践应用。通过实战案例解析接口抽象、错误处理、配置管理、日志监控等关键工程化技术,帮助开发者掌握构建稳定、可扩展Go应用的最佳实践方法。

2

2026.02.28

Golang 性能分析与运行时机制:构建高性能程序
Golang 性能分析与运行时机制:构建高性能程序

Go语言以其高效的并发模型和优异的性能表现广泛应用于高并发、高性能场景。其运行时机制包括 Goroutine 调度、内存管理、垃圾回收等方面,深入理解这些机制有助于编写更高效稳定的程序。本专题将系统讲解 Golang 的性能分析工具使用、常见性能瓶颈定位及优化策略,并结合实际案例剖析 Go 程序的运行时行为,帮助开发者掌握构建高性能应用的关键技能。

1

2026.02.28

Golang 并发编程模型与工程实践:从语言特性到系统性能
Golang 并发编程模型与工程实践:从语言特性到系统性能

本专题系统讲解 Golang 并发编程模型,从语言级特性出发,深入理解 goroutine、channel 与调度机制。结合工程实践,分析并发设计模式、性能瓶颈与资源控制策略,帮助将并发能力有效转化为稳定、可扩展的系统性能优势。

13

2026.02.27

热门下载

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

精品课程

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

共23课时 | 4万人学习

C# 教程
C# 教程

共94课时 | 10.4万人学习

Java 教程
Java 教程

共578课时 | 74.2万人学习

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

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