Java源码阅读之AtomicStampedReference

21 篇文章 0 订阅
7 篇文章 0 订阅

AtomicStampedReference源码分析

问题

  1. AtomicStampedReference是什么?
  2. AtomicStampedReference怎么解决ABA问题?

参考

彤哥读源码

https://mp.weixin.qq.com/s?__biz=Mzg2ODA0ODM0Nw==&mid=2247483882&idx=1&sn=67b9e3769e9eba716eaee54f22c3d7af&scene=21#wechat_redirect

一:简介

AtomicStampedReference是Java并发包下面提供的一个原子类,它能解决其他原子类无法解决的ABA问题。

ABA问题在前面的Unsafe类学习中有提到。它发生在多线程环境中,当某线程连续读取同一块内存地址两次,两次得到的值一样,它简单地认为“此内存地址的值并没有被修改过”,然而,同时可能存在另一个线程在着这两次读取之间把这个内存地址的值从A修改成了B又修改回了A,这时还简单地认为“没有修改过”显然是错误的。

彤哥在他的文章中举了两个很好的例子来表明ABA的问题,很形象。

二:源码分析

属性

    // 内部定义类Pair<T>,两个属性,reference,stamp,将元素值和版本号绑定在一起
    private static class Pair<T> {
        final T reference;
        final int stamp;
        private Pair(T reference, int stamp) {
            this.reference = reference;
            this.stamp = stamp;
        }
        static <T> Pair<T> of(T reference, int stamp) {
            return new Pair<T>(reference, stamp);
        }
    }    
    // 声明一个Pair类型变量,在上面已经定义
    private volatile Pair<V> pair;
    // 获取Unsafe实例
    private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
    // 获取pair变量的偏移量,方便寻址
    private static final long pairOffset =
        objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);          

方法

构造方法
    public AtomicStampedReference(V initialRef, int initialStamp) {
        pair = Pair.of(initialRef, initialStamp);
    }

构造方法只有一个,需要传入两个参数,一个是初始值,一个是初始版本号。

普通get/set方法
    // 返回值
    public V getReference() {
        return pair.reference;
    }
    // 返回版本号
    public int getStamp() {
        return pair.stamp;
    }
    // 返回值,参数接收版本号	
    public V get(int[] stampHolder) {
        Pair<V> pair = this.pair;
        stampHolder[0] = pair.stamp;
        return pair.reference;
    }

    public void set(V newReference, int newStamp) {
        Pair<V> current = pair;
        if (newReference != current.reference || newStamp != current.stamp)
            this.pair = Pair.of(newReference, newStamp);
    }
compareAndSet()方法
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        // 获取当前pair
        Pair<V> current = pair;
        return
            // 判断当前reference有没有变化
            expectedReference == current.reference &&
            // 判断版本号有没有变化
            expectedStamp == current.stamp &&
            // 判断要更改的reference和版本号是否与当前的pair一致,是则不用更改,否则更新
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }
    
    private boolean casPair(Pair<V> cmp, Pair<V> val) {
        return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
    }

调用了Unsafe类中的CAS方法,实现了原子操作,并通过版本号的引入克服了ABA问题。

三:总结

整个AtomicStampedReference类的源码很简洁,构建了内部类Pair来存储元素值和版本号,通过版本号的引入来解决ABA问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值