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关心的是有没有被人动过,方法都比较简单。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM