Java引用类型原子操作类 AtomicReference的用法
/**
* 类说明:演示引用类型的原子操作类
*/
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 Stringname;
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);
}