加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

AtomicReference、AtomicStampedReference 和 AtomicMarkableRef

发布时间:2020-12-15 07:40:51 所属栏目:Java 来源:网络整理
导读:这三个都是自 JDK1.5 开始加入到 java.util.concurrent.atomic 下面的。他们都可以在 lock-free 的情况下以原子的方式更新对象引用。 ? 一、AtomicReference 以原子方式更新对象引用。 static class User { private int age; public int getAge() { return a

这三个都是自 JDK1.5 开始加入到 java.util.concurrent.atomic 下面的。他们都可以在 lock-free 的情况下以原子的方式更新对象引用。

?

一、AtomicReference

以原子方式更新对象引用。

static class User {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public User(int age) {
        this.age = age;
    }
}

public static void main(String[] args) {
    User user1 = new User(10);
    User user2 = new User(20);

    AtomicReference<User> atomicReference = new AtomicReference<>(user1);
    System.out.println(atomicReference.get().getAge());

    atomicReference.compareAndSet(user1,user2);
    System.out.println(atomicReference.get().getAge());
}

?

二、AtomicStampedReference

解决了?AtomicReference 中 CAS 操作存在的 ABA 问题。

public static void main(String[] args) {
    User user1 = new User(10);
    User user2 = new User(20);

    AtomicStampedReference<User> stampedReference = new AtomicStampedReference<>(user1,1);

    int[] stamp = new int[1];
    // 获取引用对象和对应的版本号
    System.out.println(stampedReference.get(stamp).getAge());

    int oldStamp = stamp[0];
    // 预期引用,新引用,预期版本号,新版本号
    stampedReference.compareAndSet(user1,user2,oldStamp,2);
    
    System.out.println(stampedReference.get(stamp).getAge());
}

內部定义了一个 Pair 对象,相当于给引用加了一个版本号

public class AtomicStampedReference<V> {

    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);
        }
    }

    private volatile Pair<V> pair;

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

替换时的逻辑,当引用和版本号都相同时才使用 CAS 替换

public boolean compareAndSet(V expectedReference,V newReference,int expectedStamp,int newStamp) {
    Pair<V> current = pair;
    return expectedReference == current.reference &&
                    expectedStamp == current.stamp &&
                    ((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);
}

?

三、AtomicMarkableReference

相对于?AtomicStampedReference,有时候,我们并不关心引用变量更改了几次,只是单纯的关心是否更改过

public static void main(String[] args) {
    User user1 = new User(10);
    User user2 = new User(20);

    AtomicMarkableReference<User> stampedReference = new AtomicMarkableReference<>(user1,false);

    boolean[] stamp = new boolean[1];
    // 获取引用对象和对应的状态
    System.out.println(stampedReference.get(stamp).getAge());

    boolean oldStamp = stamp[0];
    // 预期引用,新引用,预期状态,新状态
    stampedReference.compareAndSet(user1,false);

    System.out.println(stampedReference.get(stamp).getAge());
}

内部和?AtomicStampedReference 一样

public class AtomicMarkableReference<V> {

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

    private volatile Pair<V> pair;
    
    public AtomicMarkableReference(V initialRef,boolean initialMark) {
        pair = Pair.of(initialRef,initialMark);
    }

    public boolean compareAndSet(V expectedReference,boolean expectedMark,boolean newMark) {
        Pair<V> current = pair;
        return
                expectedReference == current.reference &&
                        expectedMark == current.mark &&
                        ((newReference == current.reference &&
                                newMark == current.mark) ||
                                casPair(current,newMark)));
    }

    private boolean casPair(Pair<V> cmp,Pair<V> val) {
        return UNSAFE.compareAndSwapObject(this,val);
    }

?


https://segmentfault.com/a/1190000015831791

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读