• AtomicReference、AtomicStampedReference 和 AtomicMarkableReference


    这三个都是自 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, user2, oldStamp, 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, V newReference, boolean expectedMark, boolean newMark) {
            Pair<V> current = pair;
            return
                    expectedReference == current.reference &&
                            expectedMark == current.mark &&
                            ((newReference == current.reference &&
                                    newMark == current.mark) ||
                                    casPair(current, Pair.of(newReference, newMark)));
        }
    
        private boolean casPair(Pair<V> cmp, Pair<V> val) {
            return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
        }

    https://segmentfault.com/a/1190000015831791

  • 相关阅读:
    HDU 1863 畅通project (最小生成树是否存在)
    经常使用MD5算法代码
    HDU 5045(Contest-费用流)[template:费用流]
    【c语言】统计一个数二进制中的1的个数
    git
    如何在阿里云服务器里配置iis 搭建web服务
    war包放入tomcat
    互联网推送服务原理:长连接+心跳机制(MQTT协议)
    保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护 3
    保持Service不被Kill掉的方法--双Service守护 && Android实现双进程守护 2
  • 原文地址:https://www.cnblogs.com/jhxxb/p/11552150.html
Copyright © 2020-2023  润新知