JAVA并发-AtomicStampedReference

AtomicStampedReference 类提供了对对象引用变量的原子读和写, AtomicStampedReference是指多个试图更改同一AtomicStampedReference的线程不会使AtomicStampedReference最终处于不一致的状态。

AtomicStampedReference AtomicReference 不一样的是,AtomicStampedReference在内部同时保留对象引用和数据戳,引用和数据戳可以通过compareAndSet()方法使用单CAS操作进行交换.

AtomicStampedReference设计是为了解决AtomicReference 不能解决的ABA问题,ABA问题后面会讲解。

创建AtomicStampedReference

创建 AtomicStampedReference实例:

Object initialRef   = null;
int    initialStamp = 0;

AtomicStampedReference atomicStampedReference =
    new AtomicStampedReference(intialRef, initialStamp);

 

创建有类型的AtomicStampedReference

可以通过泛型创建指定类型的AtomicStampedReference,下面是代码:

String initialRef   = null;
int    initialStamp = 0;

AtomicStampedReference<String> atomicStampedReference =
    new AtomicStampedReference<String>(
        initialRef, initialStamp
    );

 

创建了一个String类型的 AtomicStampedReference,如果知道引用的类型,一般建议使用AtomicStampedReference 时使用泛型。

获取AtomicStampedReference引用

可以通过AtomicStampedReference的getReference方法获取存储在AtomicStampedReference中的引用。如果不使用泛型,getReference()将返回Object对象的引用,如果使用了泛型,将返回创建AtomicStampedReference 变量时时候使用的泛型,下面是首先是不使用泛型 AtomicStampedReference getReference()例子:

String initialRef = "first text";

AtomicStampedReference atomicStampedReference = (String)
    new AtomicStampedReference(initialRef, 0);

String reference = atomicStampedReference.getReference();

 

注意有必要将getReference()返回的引用强制转换为字符串,因为在AtomicStampedReference为非类型化时,getReference()将返回一个对象引用。

下面是使用泛型的AtomicStampedReference 例子:

String initialRef = "first text";

AtomicStampedReference<String> atomicStampedReference =
    new AtomicStampedReference<String>(
        initialRef, 0
    );

String reference = atomicStampedReference.getReference();

 

注意,这儿不再需要使用强制类型转换,因为使用了泛型,在编译时候已经知道了返回的是String引用。

获取AtomicStampedReference的数据戳

AtomicStampedReference 同时还有一个getStamp() 方法,用来获取内部存储的数据戳,下面是代码:

String initialRef = "first text";

AtomicStampedReference<String> atomicStampedReference =
    new AtomicStampedReference<>(initialRef, 0);

int stamp = atomicStampedReference.getStamp();

 

原子性获取引用和数据戳

AtomicStampedReference 可以通过一个简单的,原子操作get()方法同时获取到引用和数据戳,可以将int类型的数组作为参数传到get()方法,并返回引用类型,同时数据戳会存储在int类型数组的第一个元素,下面是代码:

String initialRef   = "text";
String initialStamp = 0;

AtomicStampedReference<String> atomicStampedReference =
    new AtomicStampedReference<>(
        initialRef, initialStamp
    );

int[] stampHolder = new int[1];
String ref = atomicStampedReference.get(stampHolder);

System.out.println("ref = " + ref);
System.out.println("stamp = " + stampHolder[0]);

 

设置AtomicStampedReference的引用

可以通过AtomicStampedReference实例的set()方法存储引用. 在没有使用 AtomicStampedReference实例的set()方法中第一个参数是使用的 Object对象引用,在使用泛型的 AtomicStampedReferenceset()方法第一个参数是定义时的泛型类型,下面是

AtomicStampedReference set()代码:

AtomicStampedReference<String> atomicStampedReference =
     new AtomicStampedReference<>(null, 0);


String newRef = "New object referenced";
int    newStamp = 1;

atomicStampedReference.set(newRef, newStamp);

 

我们看到无论使不使用泛型的set()方法都没有什么区别,唯一的不一样是编译的时候应该控制了类型

CAS操作AtomicStampedReference引用

AtomicStampedReference类包含了一个有用的 compareAndSet()方法, compareAndSet()方法将一个期望的引用与存储在 AtomicStampedReference实例中的值比较,如果引用与数据戳都相等(equals()或者 ==),那么 AtomicStampedReference实例将被设置为新的引用,compareAndSet()如果设置成功将返回ture否则返回false.下面是AtomicStampedReference compareAndSet()例子:

String initialRef   = "initial value referenced";
int    initialStamp = 0;

AtomicStampedReference<String> atomicStringReference =
    new AtomicStampedReference<String>(
        initialRef, initialStamp
    );

String newRef   = "new value referenced";
int    newStamp = initialStamp + 1;

boolean exchanged = atomicStringReference
    .compareAndSet(initialRef, newRef, initialStamp, newStamp);
System.out.println("exchanged: " + exchanged);  //true

exchanged = atomicStringReference
    .compareAndSet(initialRef, "new string", newStamp, newStamp + 1);
System.out.println("exchanged: " + exchanged);  //false

exchanged = atomicStringReference
    .compareAndSet(newRef, "new string", initialStamp, newStamp + 1);
System.out.println("exchanged: " + exchanged);  //false

exchanged = atomicStringReference
    .compareAndSet(newRef, "new string", newStamp, newStamp + 1);
System.out.println("exchanged: " + exchanged);  //true

 

例子首先创建了 AtomicStampedReference,然后通过compareAndSet()设置引用和数据戳,第二次在调用 compareAndSet()没有成功,因为第一次的 initialRef  与存储值一样,这时内部存储的是newRef,所以在调用compareAndSet()失败。

第二段,首先initialStamp  与期望值newStamp 不一样更新失败,此时存储的为newStamp  ,再次调用compareAndSet()则成功。

参考: https://blog.csdn.net/cgsyck/article/details/108026037

         http://tutorials.jenkov.com/java-util-concurrent/atomicstampedreference.html

        http://tutorials.jenkov.com/java-concurrency/non-blocking-algorithms.html

        http://tutorials.jenkov.com/java-generics/index.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值