CAS 的 ABA 问题-AtomicStampedReference

CAS 出现 ABA 问题,就是在多线程的场景下,一个线程把值由 A 改成 B,再由 B 改成 A,其他线程读取该变量的时候依然是 A,无感知该变量的修改,这里引入AtomicStampedReference通过版本号来解决这个问题。

单线程下AtomicStampedReference通过版本号来解决 ABA 问题。

/**
 * @author 
 * @descpription: 解决CAS的ABA问题
 * @date 2024/6/11
 */
public class AtomicStampedReferenceDemo {
    /**
     * 单线程下通过版本号解决ABA问题
     * @param args
     */
    public static void main(String[] args) {
        Book javaBook = new Book(1, "python");
        AtomicStampedReference<Book> atomicStampedReference =
                new AtomicStampedReference<>(javaBook, 1);
        System.out.println("初始数据:" + atomicStampedReference.getReference());
        System.out.println("初始版本号:" + atomicStampedReference.getStamp());
        Book mysqlBook = new Book(2, "python");
        boolean b = atomicStampedReference.compareAndSet(javaBook, mysqlBook, 1, 2);
        System.out.println("修改结果:" + b);
        System.out.println("修改后的数据:" + atomicStampedReference.getReference());
        System.out.println("修改后的版本号:" + atomicStampedReference.getStamp());
        atomicStampedReference.compareAndSet(mysqlBook, javaBook, 2, 3);
        System.out.println("修改回初始数据:" + atomicStampedReference.getReference());
        System.out.println("修改回初始版本号:" + atomicStampedReference.getStamp());
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
class Book{
    private int id;
    private String bookName;
}

下面通过 2 个案例来说明一下:

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicStampedReference;

/**
 * @descpription:  AtomicInteger出现ABA问题
 *                 AtomicStampedReference通过版本号解决这个问题
 * @date 2024/6/11
 */
public class ABADemo {
    static AtomicInteger atomicInteger = new AtomicInteger(100);
    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(100, 1);

    public static void main(String[] args) {
        abdHappenVersion();
    }

    /**
     * 通过版本号解决了ABA,多线程通过版本号来判断是否发生了ABA问题
     */
    public static void abdHappenVersion(){
        new Thread(()-> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t第一次版本号:" + stamp);
            try {TimeUnit.MILLISECONDS.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t第二次版本号:" + atomicStampedReference.getStamp());
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
            System.out.println(Thread.currentThread().getName() + "\t第三次版本号:" + atomicStampedReference.getStamp());
        },"t3").start();

        new Thread(()-> {
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + "\t第一次版本号:" + stamp);
            // 暂停1秒钟t4线程,保证t3线程完成一次ABA
            try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {throw new RuntimeException(e);}
            //由于版本号导致无法修改
            boolean a = atomicStampedReference.compareAndSet(100, 2022, stamp, stamp + 1);
            System.out.println(Thread.currentThread().getName() + "\t修改成功否:" + a + "\t当前最新实际版本号:" + stamp);
        },"t4").start();
    }

    /**
     * 无版本号出现ABA问题
     */
    public static void abdHappenNoVersion(){
        new Thread(() -> {
            atomicInteger.compareAndSet(100, 120);
            try {TimeUnit.MILLISECONDS.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}
            atomicInteger.compareAndSet(120, 100);
        },"t1").start();

        new Thread(() -> {
            try {TimeUnit.MILLISECONDS.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}
            //无版本号的约定,可以修改
            atomicInteger.compareAndSet(100, 2022);
            System.out.println("修改后的值: " + atomicInteger.get());
        },"t2").start();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值