程序员求职经验分享与学习资料整理平台

网站首页 > 文章精选 正文

JDK源码剖析之AtomicStampedReference和AtomicMarkableReference

balukai 2025-05-10 20:00:11 文章精选 4 ℃

AtomicStampedReference和AtomicMarkableReference

ABA问题与解决办法

到目前为止,CAS都是基于“值”来做比较的。但如果另外一个线程把变量的值从A改为B,再从B改回到A,那么尽管修改过两次,可是在当前线程做CAS操作的时候,却会因为值没变而认为数据没有被其他线程修改过,这就是所谓的ABA问题。

要解决 ABA 问题,不仅要比较“值”,还要比较“版本号”,而这正是 AtomicStamped-Reference做的事情,其对应的CAS函数如下:

之前的 CAS只有两个参数,这里的 CAS有四个参数,后两个参数就是版本号的旧值和新值。

当expectedReference!=对象当前的reference时,说明该数据肯定被其他线程修改过;

当expectedReference==对象当前的reference时,再进一步比较expectedStamp是否等于对象当前的版本号,以此判断数据是否被其他线程修改过。

为什么没有AtomicStampedInteger或AtomictStampedLong

要解决Integer或者Long型变量的ABA问题,为什么只有AtomicStampedReference,而没有AtomicStampedInteger或者AtomictStampedLong呢?

因为这里要同时比较数据的“值”和“版本号”,而Integer型或者Long型的CAS没有办法同时比较两个变量,于是只能把值和版本号封装成一个对象,也就是这里面的 Pair 内部类,然后通过对象引用的CAS来实现。代码如下所示。

当使用的时候,在构造函数里面传入值和版本号两个参数,应用程序对版本号进行累加操作,然后调用上面的CAS。如下所示。

AtomicMarkableReference

AtomicMarkableReference与AtomicStampedReference原理类似,只是Pair里面的版本号是boolean类型的,而不是整型的累加变量,如下所示。

因为是boolean类型,只能有true、false 两个版本号,所以并不能完全避免ABA问题,只是降低了ABA发生的概率。

本篇给大家讲解的内容是JDK源码剖析之Atomic类——AtomicStampedReference和AtomicMarkableReference

下篇文章给大家介绍的内容是JDK源码剖析之Atomic类——AtomicIntegerFieldUpdater、

AtomicLongFieldUpdater和
AtomicReferenceFieldUpdater

最近发表
标签列表