Java引用类型原子操作类 AtomicReference的用法

标签: java

/**
 * 类说明:演示引用类型的原子操作类
 */
public class UseAtomicReference {
    static AtomicReference<UserInfo> atomicUserRef;

    public static void main(String[] args) {
        UserInfo user = new UserInfo("Mark", 15);//要修改的实体的实例
        atomicUserRef = new AtomicReference(user);
        UserInfo updateUser = new UserInfo("Bill", 17);
        boolean a = atomicUserRef.compareAndSet(user, updateUser);
        System.out.println(a);
        System.out.println(atomicUserRef.get());
        System.out.println(user);
    }

    //定义一个实体类
    static class UserInfo {
        private volatile String name;
        private int age;

        public UserInfo(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }

        @Override
        public String toString() {
            return "UserInfo{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }

}

注:

atomicUserRef.compareAndSet(user, updateUser); 是改变了原有对象的引用路径,但本身的值并不会改变

 new AtomicReference(user);  将对象进行封装,使之变为原子操作

AtomicStampedReference

创建

AtomicStampedReference<String> asr=new AtomicStampedReference("djy",0);

源码为:

注:

这里可以看出AtomicStampedReference能够解决所谓的ABA问题,很简单版本号控制

 解决ABA问题

/**
 * 类说明:演示带版本戳的原子操作类
 */
public class UseAtomicStampedReference {
    static AtomicStampedReference<String> asr
            = new AtomicStampedReference("djy", 0);

    public static void main(String[] args) throws InterruptedException {
        //拿到当前的版本号(旧)
        final int oldStamp = asr.getStamp();
        final String oldReference = asr.getReference();
        System.out.println(oldReference + "============" + oldStamp);

        Thread rightStampThread = new Thread(new Runnable() {
            @Override
            public void run() {
                asr.compareAndSet(oldReference, "java", oldStamp, oldStamp + 1);
            }
        });

        Thread errorStampThread = new Thread(new Runnable() {
            @Override
            public void run() {
                String reference = asr.getReference();
                int stamp = asr.getStamp();
                asr.compareAndSet(reference, "C++", stamp, stamp + 1);
            }
        });
        rightStampThread.start();
        //让线程充分运行完毕
        rightStampThread.join();
        errorStampThread.start();
        errorStampThread.join();

        System.out.println(asr.getReference() + "============" + asr.getStamp());
    }
}

AtomicMarkableReference

用法与AtomicStampedReference基本一致

AtomicMarkableReference 与 AtomicStampedReference的区别?

AtomicStampedReference

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

AtomicStampedReference中的每一个引用变量都带上了pair.stamp这个时间戳,这样就可以解决CAS中的ABA的问题。

/**
 * Creates a new {@code AtomicStampedReference} with the given
 * initial values.
 *
 * @param initialRef the initial reference
 * @param initialStamp the initial stamp
 */
public AtomicStampedReference(V initialRef, int initialStamp) {
    pair = Pair.of(initialRef, initialStamp);
}

AtomicMarkableReference

AtomicStampedReference可以知道,引用变量中途被更改了几次。有时候,我们并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference。

AtomicMarkableReference的唯一区别就是不再用int标识引用,而是使用boolean变量——表示引用变量是否被更改过。

构造函数

/**
 * Creates a new {@code AtomicMarkableReference} with the given
 * initial values.
 *
 * @param initialRef the initial reference
 * @param initialMark the initial mark
 */
public AtomicMarkableReference(V initialRef, boolean initialMark) {
    pair = Pair.of(initialRef, initialMark);
}

 

 

 

版权声明:本文为weixin_42081445原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_42081445/article/details/104978257