zoukankan      html  css  js  c++  java
  • JDK对CAS ABA问题解决-AtomicMarkableReference和AtomicStampedReference

    我们知道AtomicInteger和AtomicLong的原子操作,但是在这两个类在CAS操作的时候会遇到ABA问题,可能大家会疑问什么是ABA问题呢,请待我细细道来:

    ABA问题:简单讲就是多线程环境,2次读写中一个线程修改A->B,然后又B->A,另一个线程看到的值未改变,又继续修改成自己的期望值。当然我们如果不关心过程,只关心结果,那么这个就是无所谓的ABA问题。

    • 为了解决ABA问题,伟大的java为我们提供了AtomicMarkableReference和AtomicStampedReference类,为我们解决了问题
    • AtomicStampedReference是利用版本戳的形式记录了每次改变以后的版本号,这样的话就不会存在ABA问题了,在这里我借鉴一下别人举得例子

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

    • 我写了个代码,大家请看
    import java.util.concurrent.atomic.AtomicStampedReference;
    public class AtomicStampedReferenceTest {
        static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference(0, 0);
        public static void main(String[] args) throws InterruptedException {
            final int stamp = atomicStampedReference.getStamp();
            final Integer reference = atomicStampedReference.getReference();
            System.out.println(reference+"============"+stamp);
            Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                    System.out.println(reference + "-" + stamp + "-"
                    + atomicStampedReference.compareAndSet(reference, reference + 10, stamp, stamp + 1));
            }
            });
    
            Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                    Integer reference = atomicStampedReference.getReference();
                    System.out.println(reference + "-" + stamp + "-"
                    + atomicStampedReference.compareAndSet(reference, reference + 10, stamp, stamp + 1));
            }
            });
            t1.start();
            t1.join();
            t2.start();
            t2.join();
    
            System.out.println(atomicStampedReference.getReference());
            System.out.println(atomicStampedReference.getStamp());
        }
    }

    输出结果:

    0============0
    0-0-true
    10-0-false
    10
    1

    结论:可以看出第二次更新的时候,失败了,因为版本号已经被改变了,所以AtomicStampedReference帮我们解决了CAS操作中的ABA问题!

    AtomicMarkableReference跟AtomicStampedReference差不多, 
    AtomicStampedReference是使用pair的int stamp作为计数器使用,AtomicMarkableReference的pair使用的是boolean mark。 
    还是那个水的例子,AtomicStampedReference可能关心的是动过几次,AtomicMarkableReference关心的是有没有被人动过,方法都比较简单。

  • 相关阅读:
    2006年百度之星程序设计大赛试题初赛题目题4剪刀石头布
    2006年百度之星程序设计大赛试题初赛题目题5座位调整
    Linux2.6用户空间堆栈区的分配与回收
    Linux2.6物理内存管理
    2006年百度之星程序设计大赛试题初赛题目题6百度语言翻译机
    带权的二分匹配
    二分图带权匹配KuhnMunkres算法(有修改)
    Linux2.6虚拟内存管理
    Linux2.6为数据结构分配内存slab
    2012225面试题目
  • 原文地址:https://www.cnblogs.com/barrywxx/p/8687653.html
Copyright © 2011-2022 走看看