AtomicStampedReference 源码分析

AtomicStampedReference

AtomicStampedReference 能解决什么问题?什么时候使用 AtomicStampedReference?

1)AtomicStampedReference 维护带有整数标识的对象引用,可以用原子方式对其进行更新。
2)AtomicStampedReference 能够解决 CAS 的 ABA 问题。

如何使用 AtomicStampedReference?

1)使用 AtomicStampedReference 解决无锁 CAS 过程中的 ABA 问题,特别是涉及资金时。

使用 AtomicStampedReference 有什么风险?

1)高并发场景下,自旋 CAS 长时间失败会导致 CPU 飙升

AtomicStampedReference 核心操作的实现原理?

创建实例

    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<>(reference, stamp);
        }
    }

    private volatile Pair<V> pair;

    /**
     * 创建具有给定对象引用和标识值的新 AtomicStampedReference 实例
     */
    public AtomicStampedReference(V initialRef, int initialStamp) {
        pair = Pair.of(initialRef, initialStamp);
    }

尝试原子更新

    /**
     * 如果旧引用==expectedReference && 旧整形标记==expectedStamp,
     * 则尝试原子更新引用为 newReference,时间标记为 newStamp
     */
    public boolean compareAndSet(V   expectedReference,
            V   newReference,
            int expectedStamp,
            int newStamp) {
        final Pair<V> current = pair;
        return
                expectedReference == current.reference &&
                expectedStamp == current.stamp &&
                (newReference == current.reference &&
                newStamp == current.stamp ||
                casPair(current, Pair.of(newReference, newStamp)));
    }

读取值

    /**
     *  读取引用值
     */
    public V getReference() {
        return pair.reference;
    }

    /**
     *  读取整形标记
     */
    public int getStamp() {
        return pair.stamp;
    }

    /**
     *  读取引用值,并将整形标记存储到形参数组索引为 0 的位置
     */
    public V get(int[] stampHolder) {
        final Pair<V> pair = this.pair;
        stampHolder[0] = pair.stamp;
        return pair.reference;
    }

写入值

    /**
     * 无条件地更新引用值和时间标记
     */
    public void set(V newReference, int newStamp) {
        final Pair<V> current = pair;
        if (newReference != current.reference || newStamp != current.stamp) {
            this.pair = Pair.of(newReference, newStamp);
        }
    }

原子更新值,并发更新时可能失败

    /**
     * 如果旧引用==expectedReference && 旧整形标记==expectedStamp,
     * 则尝试原子更新引用为 newReference,时间标记为 newStamp
     */
    public boolean weakCompareAndSet(V   expectedReference,
            V   newReference,
            int expectedStamp,
            int newStamp) {
        return compareAndSet(expectedReference, newReference,
                expectedStamp, newStamp);
    }

    /**
     * 如果旧引用==expectedReference && 旧整形标记==expectedStamp,
     * 则尝试原子更新引用为 newReference,时间标记为 newStamp
     */
    public boolean compareAndSet(V   expectedReference,
            V   newReference,
            int expectedStamp,
            int newStamp) {
        final Pair<V> current = pair;
        return
                expectedReference == current.reference &&
                expectedStamp == current.stamp &&
                (newReference == current.reference &&
                newStamp == current.stamp ||
                casPair(current, Pair.of(newReference, newStamp)));
    }

    private static final VarHandle PAIR;
    static {
        try {
            final MethodHandles.Lookup l = MethodHandles.lookup();
            PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
                    Pair.class);
        } catch (final ReflectiveOperationException e) {
            throw new Error(e);
        }
    }

    private boolean casPair(Pair<V> cmp, Pair<V> val) {
        return AtomicStampedReference.PAIR.compareAndSet(this, cmp, val);
    }
原文地址:https://www.cnblogs.com/zhuxudong/p/10055081.html