高并发编程之AtomicStampedReference讲解

一、AtomicStampedReference介绍

①.AtomicStampedReference用来解决AtomicInteger中的“ABA”问题。
②.AtomicStampedReference内部不仅维护了对象值,还维护了一个时间戳(我这里把它称为时间戳,实际上它可以使任何一个整数,它使用整数来表示状态值)。当AtomicStampedReference对应的数值被修改时,除了更新数据本身外,还必须要更新时间戳。当AtomicStampedReference设置对象值时,对象值以及时间戳都必须满足期望值,写入才会成功。因此,即使对象值被反复读写,写回原值,只要时间戳发生变化,就能防止不恰当的写入。

二、什么是ABA问题

ABA并不是一个缩写,更像是一个形象的描述。ABA问题出现在多线程或多进程计算环境中。
首先描述ABA。假设两个线程T1和T2访问同一个变量V,当T1访问变量V时,读取到V的值为A;此时线程T1被抢占了,T2开始执行,T2先将变量V的值从A变成了B,然后又将变量V从B变回了A;此时T1又抢占了主动权,继续执行,它发现变量V的值还是A,以为没有发生变化,所以就继续执行了。这个过程中,变量V从A变为B,再由B变为A就被形象地称为ABA问题了。

三、ABA问题的解决方案

①.为了解决ABA问题,伟大的java为我们提供了AtomicMarkableReference和AtomicStampedReference类,为我们解决了问题,在这里我们只讲AtomicStampedReference类。
②.AtomicStampedReference是利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在ABA问题了。

在这里我借鉴一下别人举得例子:
举个通俗点的例子,你倒了一杯水放桌子上,干了点别的事,然后同事把你水喝了又给你重新倒了一杯水,你回来看水还在,拿起来就喝,如果你不管水中间被人喝过,只关心水还在,这就是ABA问题。如果你是一个讲卫生讲文明的小伙子,不但关心水在不在,还要在你离开的时候水被人动过没有,因为你是程序员,所以就想起了放了张纸在旁边,写上初始值0,别人喝水前麻烦先做个累加才能喝水。这就是AtomicStampedReference的解决方案。

四、AtomicStampedReference常用方法

①.attemptStamp()方法:如果当前引用 == 预期引用,则以原子方式将该标志的值设置为给定的更新值。

package chapter3.atomicstampedreference;

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author czd
 */
public class AtomicStampedReferenceTest {
    public static void main(String[] args) {
        //1、 如果当前引用 == 预期引用,则以原子方式将该标志的值设置为给定的更新值。
        String expectedReference = "abc";
        String newReference = "def";
        AtomicStampedReference<String> atomicStampedReference = new AtomicStampedReference<>(expectedReference,1);
        Boolean bool = atomicStampedReference.attemptStamp("abc" , 5);
        System.out.println("Boolean: " + bool);
        System.out.println("atomicStampedReference : reference  " + atomicStampedReference.getReference());
        System.out.println("atomicStampedReference : stampe  " + atomicStampedReference.getStamp());

    }
}

②.compareAndSet()方法:如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。

package chapter3.atomicstampedreference;

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author czd
 */
public class AtomicStampedReferenceTest {
    public static void main(String[] args) {
        String expectedReference = "abc";
        String newReference = "def";
        //2、如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。
        AtomicStampedReference<String> atomicStampedReference1 = new AtomicStampedReference<>(expectedReference,1);
        Boolean bool1 = atomicStampedReference1.compareAndSet("abc" , "edf",1,10);
        System.out.println("Boolean: " + bool1);
        System.out.println("atomicStampedReference : reference  " + atomicStampedReference1.getReference());
        System.out.println("atomicStampedReference : stampe  " + atomicStampedReference1.getStamp());

    }
}

③.set()方法:无条件地同时设置该引用和标志的值。

package chapter3.atomicstampedreference;

import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @author czd
 */
public class AtomicStampedReferenceTest {
    public static void main(String[] args) {
        String expectedReference = "abc";
        String newReference = "def";
        //3、无条件地同时设置该引用和标志的值。
        AtomicStampedReference<String> atomicStampedReference2 = new AtomicStampedReference<>(expectedReference , 10);
        System.out.println("atomicStampedReference : reference  " + atomicStampedReference2.getReference());
        System.out.println("atomicStampedReference : stampe  " + atomicStampedReference2.getStamp());
        atomicStampedReference2.set(newReference,100);
        System.out.println("atomicStampedReference : reference  " + atomicStampedReference2.getReference());
        System.out.println("atomicStampedReference : stampe  " + atomicStampedReference2.getStamp());
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值