说到CAS理论,在java中我们第一个就想到了atomic类,一般常见的有AtomicInteger、AtomicBoolean等java.util.concurrent包下面的类,但是这个只能并发修改一个属性,如果我需要对多个属性同时进行并发修改,并且保证原子性呢?
AtomicReference 了解下?
AtomicReference也是java.util.concurrent包下的类,跟AtomicInteger等是一样的,也是基于CAS无锁理论实现的,但是不同的是 AtomicReference 是操控多个属性的原子性的并发类
在看看如何使用之前,我们先来介绍一个方法:
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
官方的解释是:
Atomically sets the value to the given updated value
主要的作用是通过比对两个对象,然后更新为新的对象
这里需要注意下,这里的比对两个对象,比对的方式不是equals
而是==
,意味着比对的是内存的中地址,这个我们可以通过unsafe.compareAndSwapObject()
方法查看,他是一个native方法
了解了上面的方法,我们来看下AtomicReference是如何使用的
模拟一个场景,在高并发的场景中,根据业务的需要,要求同时更新sequence和timestamp
/**
* Copyright © 2018 五月工作室. All rights reserved.
*
* @Project: tools
* @ClassName: AtomicReferenceDemo
* @Package: com.amos.tools.common.bean
* @author: zhuqb
* @Description: 主要用来展示AtomicReference使用方法
* @date: 2019/9/11 0011 上午 9:46
* @Version: V1.0
*/
public class AtomicReferenceDemo {
private Reference reference;
private AtomicReference<Reference> atomicReference;
/**
* 构建器中初始化AtomicReference
*
* @param reference
*/
public AtomicReferenceDemo(Reference reference) {
this.reference = reference;
this.atomicReference = new AtomicReference<>(reference);
}
public void atomic(Reference reference) {
Reference referenceOld;
Reference referenceNew;
long sequence;
long timestamp;
while (true) {
referenceOld = this.atomicReference.get();
sequence = referenceOld.getSequence();
sequence++;
timestamp = System.currentTimeMillis();
referenceNew = new Reference(sequence, timestamp);
/**
* 比较交换
*/
if (this.atomicReference.compareAndSet(referenceOld, referenceNew)) {
reference.setSequence(sequence);
reference.setTimestamp(timestamp);
break;
}
}
}
}
/**
* 业务场景模拟
* 序列需要自增并且时间需要更新成最新的时间戳
*/
@Data
@AllArgsConstructor
class Reference {
/**
* 序列
*/
private long sequence;
/**
* 时间戳
*/
private long timestamp;
}
上述代码的逻辑如下:
- 获取并缓存原来的变量,这个变量包含原来的序列和时间戳
- 基于原来的变量来更新新的时间戳和序列
- 计算后,使用CAS操作更新原来的变量,更新的过程中,需要传递保存原来的变量
- 如果保存的原来变量被其他线程修改了,就需要在这里重新拿到最新的变量,并再次计算和重试更新