CAS带来的ABA问题以及解决方案

CAS带来的ABA问题

在这里插入图片描述
线程1和线程2同时对变量i = 1 进行操作,线程1对i进行了两次操作,先将i+1 写出,后又进行了i-1并写出,线程2过来读的时候与原来值1仍然是相等的,虽然值仍然相等,但是i的值却发生过改变,期间从1变成2又变成1(ABA问题)。

解决方案

对值的每次操作都进行记录,需要保证是一个原子操作。
在这里插入图片描述
java中使用AtomicMarkableReference或者AtomicStampedReference。
AtomicMarkableReference:使用boolean表示是否修改过。
AtomicStampedReference: 使用int 记录改变的次数(推荐)!

AtomicStampedReference 使用:

class Stu {
    private String name;
    private Integer age;
getter/setter
}

//参数1: 对象 
//参数2:初始版本号
 AtomicStampedReference<Stu> accountBalance = new AtomicStampedReference<>(stu, 0);
 
源码:
public AtomicStampedReference(V var1, int var2) {
    this.pair = AtomicStampedReference.Pair.of(var1, var2);
}
static <T> Pair<T> of(T var0, int var1) {
    return new Pair(var0, var1);  //底层使用Pair对象。
}

private Pair(T var1, int var2) {
    this.reference = var1;  //真实对象
    this.stamp = var2;   //版本号
}
Thread threadA = new Thread(() -> {
            int[] stampHolder = new int[1];
            //获取对象
            Stu stu1 = accountBalance.get(stampHolder);

            //改变的次数
            int currentStamp = stampHolder[0];
            System.out.println("Thread A: 当前年龄 = " + stu1.getAge() + ", 当前版本号= " + currentStamp);

            stu1.setAge(100000);
            boolean success = accountBalance.compareAndSet(stu1, stu1, currentStamp, currentStamp + 1);
            /**
             *源码:
             * 参数1:  期望值
             * 参数2:  新值
             * 参数3: 原有修改次数
             * 参数4: 新修改次数(一般使用原有修改次数+1)
             *    public boolean compareAndSet(V var1, V var2, int var3, int var4) {
             *
             *         //原始对象值  包含对象和修改的次数
             *         Pair var5 = this.pair;
             *         return
             *              var1 == var5.reference  //对象不是同一个(期望值不一样)  就不再进行操作
             *              && var3 == var5.stamp   // 版本号不一样  就不再进行操作
             *              && (var2 == var5.reference && var4 == var5.stamp   //操作对象与原来一样并且操作次数也一样 表示中间的值没有被其他线程修改过,无需继续修改
             *                      ||
             *                  this.casPair(var5, AtomicStampedReference.Pair.of(var2, var4)));  //进行CAS操作
             *     }
             *
             *
             *
             *
             *
             */

            if (success) {
                System.out.println("Thread A: 更新成功,新的年龄 = " + accountBalance.getReference().getAge() + ",新的版本号" + accountBalance.getStamp());
            } else {
                System.out.println("Thread A: 更新失败");
            }
        });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值