• ABA问题的产生及解决


    什么是ABA问题

    在CAS算法中,需要取出内存中某时刻的数据(由用户完成),在下一时刻比较并交换(CPU保证原子操作),这个时间差会导致数据的变化。

    1、线程1从内存位置V中取出A
    2、线程2从内存位置V中取出A
    3、线程2进行了写操作,将B写入内存位置V
    4、线程2将A再次写入内存位置V
    5、线程1进行CAS操作,发现V中仍然是A,交换成功

    尽管线程1的CAS操作成功,但线程1并不知道内存位置V的数据发生过改变

    ABA问题本质:

    根本在于CAS在修改变量的时候,无法记录变量的状态,比如是否修改过这个变量,修改的次数。

    public class ABADemo {
        
        private static AtomicReference<Integer> atomicReference = new AtomicReference<Integer>(100);
    
        public static void main(String[] args) {
            new Thread(() -> {
                Integer a = atomicReference.get();
                atomicReference.compareAndSet(a, 101);
                atomicReference.compareAndSet(101, a);
                System.out.println("t1修改了atomicReference的值");
            },"t1").start();
            
            new Thread(() -> {
                Integer b = atomicReference.get();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(atomicReference.compareAndSet(b, 2019) + "	修改后的值:" + atomicReference.get());
            },"t2").start();
        }
    }

     ABA问题怎么解决

    public class AtomicStampedReferenceTest {
        
        private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(100,1);
    
        public static void main(String[] args) {
            new Thread(() -> {
                Integer stamp = atomicStampedReference.getStamp();
                System.out.println("t1拿到的初始版本号:"  + stamp);
                //睡眠1秒,是为了让t2线程也拿到同样的初始版本号
                try {
                   Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                atomicStampedReference.compareAndSet(100, 101,stamp,stamp+1);
                stamp = atomicStampedReference.getStamp();
                atomicStampedReference.compareAndSet(101, 100,stamp,stamp+1);
            },"t1").start();
            
            new Thread(() -> {
                int stamp = atomicStampedReference.getStamp();
                System.out.println("t2拿到的初始版本号:" + stamp);
                //睡眠3秒,是为了让t1线程完成ABA操作
                try {
                    Thread.sleep(3000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                System.out.println("最新版本号:" + atomicStampedReference.getStamp());
                System.out.println(atomicStampedReference.compareAndSet(100, 2019,stamp,atomicStampedReference.getStamp() + 1) + "	当前 值:" + atomicStampedReference.getReference());
            },"t2").start();
        }
    }

    如果不关心引用变量更改了几次,只单纯的关心是否更改过,可以使用AtomicMarkableReference

    public class ABADemo {
        
        private static AtomicMarkableReference<Integer> atomicMarkableReference = new AtomicMarkableReference<Integer>(100,false);
    
        public static void main(String[] args) {
            new Thread(() -> {
                System.out.println("t1版本号是否被更改:" + atomicMarkableReference.isMarked());
                //睡眠1秒,是为了让t2线程也拿到同样的初始版本号
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                atomicMarkableReference.compareAndSet(100, 101,false,true);
              
            },"t1").start();
            
            new Thread(() -> {
                boolean isMarked = atomicMarkableReference.isMarked();
                System.out.println("t2版本号是否被更改:" + isMarked);
                //睡眠3秒,是为了让t1线程执行
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("是否更改过:" + atomicMarkableReference.isMarked());
                System.out.println(atomicMarkableReference.compareAndSet(100, 2019,isMarked,true) + "	当前 值:" + atomicMarkableReference.getReference());
            },"t2").start();
        }
    }
  • 相关阅读:
    解决Altera家的ROM仿真数据一直为0
    解决sublime text3 中文字符乱码
    sublime3添加verilog自动补全代码段
    慢腾腾的Quartus prime16.0加快编译速度
    Quartus prime16.0 与modelsim ae 联调
    JTAG基础知识
    Quartus prime 16.0 中通过JTAG固化程序
    FPGA功能仿真,门级仿真,后仿真的区别
    testbench中$display查看例化model里面信号方法以及$realtime用法
    PHP 批量移动文件改名
  • 原文地址:https://www.cnblogs.com/moris5013/p/11824993.html
Copyright © 2020-2023  润新知