【AtomicReference、AtomicStampedReference】常规用法

本文详细介绍了Java并发包中AtomicReference与AtomicStampedReference的使用方法,包括构造方法、比较并交换、获取并更新等功能,并解释了如何解决ABA问题。

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

1. 构造

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

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

有参构造,初始化为initValue

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

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

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

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

3. 取值并更新

V getAndSet(V newValue) 返回旧值

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

 

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

V getAndUpdate(UnaryOperator<V> updateFunction) 返回旧值

V updateAndGet(UnaryOperator<V> updateFunction) 返回新值

AtomicReference<Person> 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<V> accumulatorFunction) 返回旧值

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

AtomicReference<Person> 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<Person> 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<String> reference = new AtomicStampedReference<>("Hello", 1);
System.out.println(reference.getReference());
System.out.println(reference.getStamp());

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

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

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

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

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

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

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

4. 尝试修改标签attemptStamp()

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值