0

0

详解Java并发中的AtomicMarkableReference_用于对象标记状态的原子原子更新

P粉602998670

P粉602998670

发布时间:2026-02-17 14:00:11

|

856人浏览过

|

来源于php中文网

原创

atomicmarkablereference 是用于原子更新“带布尔标记的引用”的类,解决引用不变但逻辑状态(如删除、锁定)需同步变更的竞态问题;它通过内部版本戳防aba,仅暴露boolean标记,适用于双态场景,使用时必须用get(boolean[])获取最新快照再cas。

详解java并发中的atomicmarkablereference_用于对象标记状态的原子原子更新

AtomicMarkableReference 是什么,什么时候非用不可

它解决的是“带标记的引用”需要原子更新的场景,比如一个对象本身没变,但它的逻辑状态(如是否已删除、是否被锁定)变了,你既要读取对象,又要同时读取/更新这个标记,且整个操作不能被其他线程打断。普通 AtomicReference 只能保证引用更新原子,没法附带一个布尔标记;而用两个独立的原子变量(AtomicReference + AtomicBoolean)又无法保证二者更新的整体原子性——这就是 AtomicMarkableReference 存在的唯一理由。

  • 标记只能是 boolean,不是任意类型
  • 内部用“版本戳+标记”方式实现 ABA 防御,但不暴露版本号,只暴露标记
  • 适用于轻量级双态标记:例如缓存项是否已失效、节点是否已被逻辑删除、连接是否处于“正在关闭”状态

compareAndSet 怎么写才不会白忙活

compareAndSet 要求你提供「旧引用值」「旧标记值」「新引用值」「新标记值」四个参数,任何一项不匹配都会失败。常见错误是只关心引用是否相同,却忽略标记当前值。

  • 必须先调用 getget(boolean[]) 拿到当前的引用和标记快照,再基于这个快照构造 compareAndSet 调用
  • 错误示范:ref.compareAndSet(oldObj, newObj, true, true) —— 这里 oldObj 可能早已被别的线程替换成 newObj,但标记已是 false,这次调用必然失败
  • 正确做法是用 boolean[] holder = new boolean[1] 接收标记,再传给 compareAndSet
    boolean[] mark = new boolean[1];
    Node current = ref.get(mark);
    while (!ref.compareAndSet(current, current, mark[0], !mark[0])) {
      current = ref.get(mark);
    }
    

为什么 get(boolean[]) 比单独 get() 多一层必要

get() 只返回引用,丢掉了标记;get(boolean[]) 把标记写入你传入的数组第一个元素,这是唯一能一次性拿到引用+标记快照的方式。漏掉这一步,就等于在竞态条件下凭空猜标记值。

NoCode
NoCode

美团推出的零代码应用生成平台

下载
  • 数组长度必须 ≥ 1,否则抛 NullPointerException
  • 数组只是个容器,不参与原子性保障,内容由方法内部写入
  • 如果你只需要标记不需要引用,仍得调用 get(new boolean[1]),别试图绕开

和 AtomicStampedReference 选哪个

两者都防 ABA,但设计目标不同:AtomicStampedReference 带整数版本号,适合需要多状态或递增版本的场景(如重试计数、乐观锁版本);AtomicMarkableReference 只带一个布尔标记,更轻量,语义更明确。

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

  • 如果标记只有“是/否”两种含义,选 AtomicMarkableReference:代码更直白,内存占用略小(int vs boolean)
  • 如果将来可能扩展成“未开始/进行中/已失败/已重试2次”,立刻换 AtomicStampedReference
  • 别混用:拿 AtomicMarkableReference 的引用去塞进 AtomicStampedReference,编译过不了,运行也无意义

标记和引用是一体两面,拆开读就是埋雷;CAS 不是重试次数够多就能赢,而是每次重试都得基于最新快照——这点容易被忽略,尤其在嵌套条件判断里。

热门AI工具

更多
DeepSeek
DeepSeek

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

豆包大模型
豆包大模型

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

通义千问
通义千问

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

腾讯元宝
腾讯元宝

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

文心一言
文心一言

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

讯飞写作
讯飞写作

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

即梦AI
即梦AI

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

ChatGPT
ChatGPT

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

相关专题

更多
java中boolean的用法
java中boolean的用法

在Java中,boolean是一种基本数据类型,它只有两个可能的值:true和false。boolean类型经常用于条件测试,比如进行比较或者检查某个条件是否满足。想了解更多java中boolean的相关内容,可以阅读本专题下面的文章。

361

2023.11.13

java boolean类型
java boolean类型

本专题整合了java中boolean类型相关教程,阅读专题下面的文章了解更多详细内容。

37

2025.11.30

string转int
string转int

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

750

2023.08.02

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

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

572

2024.08.29

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

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

234

2025.08.29

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

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

210

2025.08.29

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

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

675

2023.08.10

pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

315

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

126

2026.02.13

热门下载

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

精品课程

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

共23课时 | 3.6万人学习

C# 教程
C# 教程

共94课时 | 9.6万人学习

Java 教程
Java 教程

共578课时 | 67.2万人学习

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

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