ABA问题,原子引用

AtomicInteger被问到CAS, ABA.

我想了一下流程: AtomicInteger -> Unsafe类 -> 自旋 -> CAS原理 -> ABA -> 原子引用更新 -> 规避ABA问题. 如果狠的会问CAS部分的CompareAndSwapInt的底层汇编(或者写/说一下unsafe.cpp类)

CAS会导致ABA问题.

ABA:狸猫换太子。

CAS重要前提是需要取出某时刻数据并在当下时刻比较替换,那么取出之前有一段时间没有取出,这段时间差会导致数据变化。e.g. 一个线程1完成工作需要10s,线程2需要2s,两个线程同时从内存位置V取出A,线程2进行了一些操作将值变为了B, 2: V是A,它取出是A,可以改:改主内存为B;之后又这样把主内存中的变为A, 然后线程1进行CAS操作,发现主内存中还是A,然后线程1操作成功:

尽管线程1操作成功,但是这个过程还是有问题的;i.e. ABA问题是因为只管开头和结尾,不管中间, 乐观锁问题。

解决ABA问题: 加版本号的原子引用. 加版本号思想类似时间戳, 原子引用: 使得可以自定义AtomicReference而不是局限于AtomicInteger那样的基本类型。

T1  100  1   ------------- 100  1
T2  100  1     101  2      100  3

JUC: AtomicStampedReference: 时间戳作为版本号. 下面用泛型为IntegeratomicReferenceatomicStampedReference类说明,就不用基本类型的AtomicXXX类了。

public class ABADemo { // ABA问题的解决    AtomicStampedReference
    public static void main(String[] args) {
        AtomicReference atomicReference = new AtomicReference<>(100);
        AtomicStampedReference atomicStampedReference = new AtomicStampedReference<>(100, (int)(System.currentTimeMillis()));

        System.out.println("------- 导致ABA问题 ---------");
        new Thread(() -> {
            System.out.println(atomicReference.compareAndSet(100, 101)+"\t"+atomicReference.get());
            System.out.println(atomicReference.compareAndSet(101, 100)+"\t"+atomicReference.get());
        }, "t1").start();

        new Thread(() -> {
            try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(atomicReference.compareAndSet(100, 2020)+"\t"+atomicReference.get());
        }, "t2").start();

        try { TimeUnit.SECONDS.sleep(4); } catch (InterruptedException e) { e.printStackTrace(); }
        System.out.println("------- ABA问题解决 ---------");

        int stamp = atomicStampedReference.getStamp();
        new Thread(() -> {
            try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(atomicStampedReference.compareAndSet(100, 101,
                    stamp, stamp+1));
            System.out.println(atomicStampedReference.getStamp());
            System.out.println(atomicStampedReference.compareAndSet(101, 100,
                    atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
            System.out.println(atomicStampedReference.getStamp());
        }, "t3").start();

        new Thread(() -> {
            try { TimeUnit.SECONDS.sleep(7); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println(atomicStampedReference.compareAndSet(100, 101,
                    stamp, stamp+1));
            System.out.println(atomicStampedReference.getStamp());
        }, "t4").start();
    }
}

你可能感兴趣的:(ABA问题,原子引用)