AtomicStampedReference实现

AtomicStampedReference解决ABA问题

AtomicStampedReference与AtomicReference差异参考:

无锁的对象引用:AtomicReference

带有时间戳的对象引用:AtomicStampedReference

AtomicStampedReference的实现

Pair类

Pair类存储原子对象以及时间戳

    private static class Pair {
        final T reference;
        final int stamp;
        private Pair(T reference, int stamp) {
            this.reference = reference;
            this.stamp = stamp;
        }
        static  Pair of(T reference, int stamp) {
            return new Pair(reference, stamp);
        }
    }

//实际替换是把pair作为一个原子对象
    private volatile Pair pair;

 


    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair current = pair;
        return
        //期待对象与时间戳必须一致,才能进行cas操作。
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }


   //实际是把pair对象作为一个原子操作对象
   private boolean casPair(Pair cmp, Pair val) {
        return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
    }

实际替换是把pair作为一个原子对象

 AtomicReference,AtomicStampedReference与AtomicMarkableReference的区别

AtomicReference

通过volatile和Unsafe提供的CAS函数实现原子操作。 自旋+CAS的无锁操作保证共享变量的线程安全
    value是volatile类型,这保证了:当某线程修改value的值时,其他线程看到的value的值都是最新的值,即修改之后的volatile的值
    通过CAS设置value。这保证了:某线程池通过CAS函数(如compareAndSet函数)设置value时,它的操作时原子性的,即线程在操作vu略时不会被中断。
但是CAS操作可能存在ABA问题。AtomicStampedReference的出现就是为了解决这问题

AtomicStampedReference

构造方法中initialStamp(时间戳)用来唯一标识引用变量,在构造器内部,实例化了一个Pair对象,Pair对象记录了对象引用和时间戳信息,采用int作为时间戳,实际使用的时候,要保证时间戳唯一(一般做成自增的),如果时间戳如果重复,还会出现ABA的问题。
AtomicStampedReference中的每一个引用变量都带上了pair.stamp这个时间戳,这样就可以解决CAS中的ABA的问题。

AtomicMarkableReference

AtomicStampedReference可以知道,引用变量中途被更改了几次。有时候,我们并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference。
AtomicMarkableReference的唯一区别就是不再用int标识引用,而是使用boolean变量——表示引用变量是否被更改过。

    private static class Pair {
        final T reference;
        final boolean mark;
        private Pair(T reference, boolean mark) {
            this.reference = reference;
            this.mark = mark;
        }
        static Pair of(T reference, boolean mark) {
            return new Pair(reference, mark);
        }
    }

关于AtomicStampedReference使用的坑

参考:https://blog.csdn.net/xybz1993/article/details/79992120

必须保证一个值的引用必须保持不变,例如装箱,拆箱会导致同一个值的对象引用会一致变化,从而导致CAS一直失败。

你可能感兴趣的:(Java并发编程,Java基础知识)