• 【AtomicReference、AtomicStampedReference】常规用法


    AtomicReference可以针对引用类型进行原子操作。

    1. 构造

    AtomicReference ar = new AtomicReference<>(new Person());
    AtomicReference ar = new AtomicReference<>();

    无参构造,相当于AutomicReference(null)

    有参构造,初始化为initValue

    2. 如果原来是A,则更新成B 

    public boolean compareAndSet(T source, T dest):source是改之前的值,Dest是改之后的值,source与当前真实值匹配了才能执行成功,返回值表示是否执行成功。

    AtomicReference ar = new AtomicReference<>(new Person());
    ar.compareAndSet(ar.get(), new Person(ar.get().getAge(), "newName"));

    这里底层判断的时候是采用的内存地址相等判断法,而不是equals方法,所以在更新值的时候,是采用复制对象的方法,而不是在原有对象的基础上修改的方式。否则自旋的意义就没有了。

    3. 取值并更新

    V getAndSet(V newValue) 返回旧值

    AtomicReference ar = new AtomicReference<>(new Person());
    ar.getAndSet(new Person(ar.get().getAge(), "newName"));
    

     

    4. 采用lambda表达式进行更新

    V getAndUpdate(UnaryOperator updateFunction) 返回旧值

    V updateAndGet(UnaryOperator updateFunction) 返回新值

    AtomicReference ar = new AtomicReference<>(new Person());
    System.out.println(ar.getAndUpdate(ele-> new Person(ele.getAge(), "newName")));
    System.out.println(ar.updateAndGet(ele-> new Person(ele.getAge() + 5, "newName")));

    此处需要注意,一定要基于原有的对象。

    5. 基于二元操作数进行更新 

    V getAndAccumulate(V x, BinaryOperator accumulatorFunction) 返回旧值

    V accumulateAndGet(V x, BinaryOperator accumulatorFunction) 返回新值

    AtomicReference ar = new AtomicReference<>(new Person());
    System.out.println(ar.getAndAccumulate(new Person(1, "temp"), (a, b) -> new Person(a.getAge() + b.getAge(), "newName")));
    System.out.println(ar.accumulateAndGet(new Person(2, "temp"), (a, b) -> new Person(a.getAge() + b.getAge(), "newName")));
    

    6. 直接更新值set()

    AtomicReference ar = new AtomicReference<>(new Person());
    ar.set(new Person(1, "temp");
    System.out.println(ar.get());
    

    7. 直接取值get() 

    AtomicReference的ABA的问题:

    当初始值为A,在cas进行时,是查看当前是否是A,这个过程并不关心中间过程,只要当前值是A即可。所以,当中间有多次改动的时候,我们无法察觉。

    AtomicStampedReference就是为了解决这个问题,他类似的给这个对象加了一个时间戳,表示对象的修改时间,这样每一次修改都会同步修改时间戳,这就可以保证时间戳是同步递增的,然后我们就知道A->B->C->A的改动了。

    1. 构造

    AtomicStampedReference reference = new AtomicStampedReference<>("Hello", 1);
    System.out.println(reference.getReference());
    System.out.println(reference.getStamp());

    此处可以通过getReference取出值,getStamp取出时间戳

    2. 如果原来是A,并且时间戳是a, 更新值为B,时间戳是b 

    AtomicStampedReference reference = new AtomicStampedReference<>("Hello", 1);
    reference.compareAndSet(reference.getReference(), "World", 2, 3); // 失败
    reference.compareAndSet(reference.getReference(), "World", 1, 2); // 成功

    必须值和时间戳同时满足,才可以更新

    3. 直接修改值和标签set()

    AtomicStampedReference reference = new AtomicStampedReference<>("Hello", 1);

    reference.set("World", reference.getStamp() + 1);

    4. 尝试修改标签attemptStamp()

    AtomicStampedReference reference = new AtomicStampedReference<>("Hello", 1);
    reference.attemptStamp(reference.getReference(), 2); 

    只有值匹配的时候,才可以修改标签

  • 相关阅读:
    探索 ArrayList 原理 - 第三节ArrayList 常用方法源码分析
    ZC-CLS381RGB颜色识别+8x8点阵指示(完)
    什么是Selenium?使用Selenium进行自动化测试!
    制作一个简单HTML个人网页网页(HTML+CSS)大话西游之大圣娶亲电影网页设计
    QT打造高效线程池异步QWebSocket 客户端
    STM32 通过USB接口读写挂载的SD卡(支持fatfs文件系统)
    Neo4J入门笔记
    万物互联时代,谷歌、亚马逊Alexa、homekit该如何选择?
    springboot+shiro+layuimini实现后台管理系统的权限控制(三)利用shiro实现对用户的授权
    tidb-cdc同步到kafka报错cdc报错CDC:ErrKafkaNewSaramaProducer
  • 原文地址:https://blog.csdn.net/Day_and_Night_2017/article/details/126277681