`
m635674608
  • 浏览: 4936904 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

CAS和ABA问题

    博客分类:
  • java
 
阅读更多

一、引言                                                                                                                          

我们先来看一个多线程的运行场景:
时间点1 :线程1查询值是否为A 
时间点2 :线程2查询值是否为A 
时间点3 :线程2比较并更新值为B 
时间点4 :线程2查询值是否为B 
时间点5 :线程2比较并更新值为A 
时间点6 :线程1比较并更新值为C

在这个线程执行场景中,2个线程交替执行。线程1在时间点6的时候依然能够正常的进行CAS操作,尽管在时间点2到时间点6期间已经发生一些意想不到的变化, 但是线程1对这些变化却一无所知,因为对线程1来说A的确还在。通常将这类现象称为ABA问题。
ABA发生了,但线程不知道。又或者链表的头在变化了两次后恢复了原值,但是不代表链表就没有变化。

   

二、ABA问题隐患                                                                                                            

获取上面的描述ABA问题带来的隐患没有直观的认识,那我们来看下维基百科上面的形象描述:

你拿着一个装满钱的手提箱在飞机场,此时过来了一个火辣性感的美女,然后她很暖昧地挑逗着你,并趁你不注意的时候,把用一个一模一样的手提箱和你那装满钱的箱子调了个包,然后就离开了,你看到你的手提箱还在那,于是就提着手提箱去赶飞机去了。

     

三、ABA问题解决                                                                                                          

复制代码
1 A a = ref.get();
2 
3 // 根据a的状态做一些操作
4 
5 // do something
6 
7 // CAS,这时候会出现ABA问题,a指向的对象可能已经变了
8 
9 ref.compareAndSet(a, b)
复制代码

   

ABA问题我们可以使用JDK的并发包中的AtomicStampedReference和 AtomicMarkableReference来解决。

   

复制代码
// 用int做时间戳

AtomicStampedReference<QNode> tail = new AtomicStampedReference<CompositeLock.QNode>(null, 0);

int[] currentStamp = new int[1];

// currentStamp中返回了时间戳信息

QNode tailNode = tail.get(currentStamp);

tail.compareAndSet(tailNode, null, currentStamp[0], currentStamp[0] + 1)
复制代码

总结: AtomicStampedReference和 AtomicMarkableReference是通过版本号(时间戳)来解决ABA问题的,我们也可以使用版本号(verison)来解决ABA。

即乐观锁每次在执行数据的修改操作时,都会带上一个版本号,一旦版本号和数据的版本号一致就可以执行修改操作并对版本号执行+1操作,否则就执行失败。

   

四、java.util.concurrent.atomic.AtomicStampedReference的源代码是如何实现的   

1. 创建一个Pair类来记录对象引用和时间戳信息,采用int作为时间戳,实际使用的时候时间戳信息要做成自增的,否则时间戳如果重复,还会出现ABA的问题。这个Pair对象是不可变对象,所有的属性都是final的, of方法每次返回一个新的不可变对象。

2. 使用一个volatile类型的引用指向当前的Pair对象,一旦volatile引用发生变化,变化对所有线程可见。

3. set方法时,当要设置的对象和当前Pair对象不一样时,新建一个不可变的Pair对象。

4. compareAndSet方法中,只有期望对象的引用和版本号和目标对象的引用和版本好都一样时,才会新建一个Pair对象,然后用新建的Pair对象和原理的Pair对象做CAS操作。

5. 实际的CAS操作比较的是当前的pair对象和新建的pair对象,pair对象封装了引用和时间戳信息。

 

复制代码
 1 private static class Pair<T> {
 2 
 3 final T reference;
 4 
 5 final int stamp;
 6 
 7 private Pair(T reference, int stamp) {
 8 
 9 this.reference = reference;
10 
11 this.stamp = stamp;
12 
13 }
14 
15 static <T> Pair<T> of(T reference, int stamp) {
16 
17 return new Pair<T>(reference, stamp);
18 
19 }
20 
21 }
22 
23    
24 
25 private volatile Pair<V> pair;
26 
27 public AtomicStampedReference(V initialRef, int initialStamp) {
28 
29 pair = Pair.of(initialRef, initialStamp);
30 
31 }
32 
33    
34 
35 public void set(V newReference, int newStamp) {
36 
37         Pair<V> current = pair;
38 
39         if (newReference != current.reference || newStamp != current.stamp)
40 
41             this.pair = Pair.of(newReference, newStamp);
42 
43     }
44 
45    
46 
47 public boolean compareAndSet(V   expectedReference,
48 
49                                  V   newReference,
50 
51                                  int expectedStamp,
52 
53                                  int newStamp) {
54 
55         Pair<V> current = pair;
56 
57         return
58 
59             expectedReference == current.reference &&
60 
61             expectedStamp == current.stamp &&
62 
63             ((newReference == current.reference &&
64 
65               newStamp == current.stamp) ||
66 
67              casPair(current, Pair.of(newReference, newStamp)));
68 
69     }
70 
71    
72 
73 private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
74 
75     private static final long pairOffset =
76 
77         objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
78 
79    
80 
81     private boolean casPair(Pair<V> cmp, Pair<V> val) {
82 
83         return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
84 
85     }
 
http://www.cnblogs.com/exceptioneye/p/5373498.html
分享到:
评论

相关推荐

    CAS下ABA问题及优化方案

    • select&set业务场景,在并发时会出现一致性问题 • 基于“值”的CAS乐观锁,可能导致ABA问题 • CAS乐观锁,必须保证修改时的“此数据”就是“彼数据”,应该由“值”比对,优化为“版本号”比对

    CAS底层原理与ABA问题.docx

    CAS(Compare And Swap)是一种无锁算法。CAS算法是乐观锁的一种实现。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当预期值A和内存值V相同时,将内存值V修改为B并返回true,否则返回false。

    CAS源码分析,以及ABA问题的解决

    CAS(比较并交换)一个小demo import java.util.concurrent.atomic.AtomicInteger; public class CasDemo { public static void main(String[] args) { //默认初始值为5,也就是主存中的值为5 AtomicInteger ...

    Java并发的CAS原理与ABA问题的讲解

    今天小编就为大家分享一篇关于Java并发的CAS原理与ABA问题的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧

    atomicReference 使用和AtomicStampedReference 解决ABA的问题.docx

    cas带来一个ABA问题 什么是ABA呢? 就是俩个线程同事操作,有可能有一个线程已经处理结束,那么第一个线程中间又一次fail操作,会在这个结果上在进行计算 t1 t2 A A-&gt;B-&gt;A A-&gt;C 那我们来看下维基百科上面的形象描述: 你...

    【原价2300!!】尚硅谷_互联网大厂高频重点面试题视频详细讲解

    上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、线程池等重点;下半场,逐步过渡到JVM和GC的知识,深度讲解多种常见OOM异常和JVM参数调优,...

    2019年互联网大厂高频重点面试题(第2季)

    上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、线程池等重点;下半场,逐步过渡到JVM和GC的知识,深度讲解多种常见OOM异常和JVM参数调优,...

    常见的Java笔试题-JVM-JUC-Core:JUCJVM核心知识点

    AtomicStampedReference和ABA问题的解决 集合类不安全问题 List CopyOnWriteArrayList Set HashSet和HashMap Map Java锁 公平锁/非公平锁 可重入锁/递归锁 锁的配对 自旋锁 读写锁/独占/共享锁 Synchronized和Lock的...

    Java高并发编程详解.md

    ```AtomicStampedReference```来解决ABA问题,类中的```compareAndSet```方法作用首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果相等,以原子方式将该引用和标记的值设置为给定的更新值。

    2019互联网面试题第2季.mmap

    上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、线程池等重点;下半场,逐步过渡到JVM和GC的知识,深度讲解多种常见OOM异常和JVM参数调优,...

    2019互联网大厂高频重点面试题 (第2季)脑图-完结.txt

    上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、线程池等重点;下半场,逐步过渡到JVM和GC的知识,深度讲解多种常见OOM异常和JVM参数调优,...

    Offers:java学习及找工作记录。包括java基础,并发,数据库,算法,网络,设计模式,spring等参考书籍,jdk1.8源码,demo,笔面试题记录及阿里巴巴java开发手册等

    优惠记录申请Java开发工程师的学习资料演示死锁螺纹池不安全集合类volatile特性线程安全单例模式CAS应用ABA问题信号倒数计时循环屏障阿里巴巴java开发手册阿里官方发布1000道互联网大厂Java工程师面试题源码学院发布...

    高级开发并发面试题和答案.pdf

    cas机制可能导致的问题ABA,什么是ABA; 程序开多少线程合适; 实现一下DCL(双重检查锁) stream 和 parallelStream区别; 实现一个阻塞队列(用Condition写生产者与消费者就)?BlockingQueue

    concurrency:并发学习

    AtomicStampReference:CAS的ABA问题 原子性-synchronized 修饰代码块:大括号括起来的代码,作用于调用的对象 修饰方法:整个方法,作用于调用的对象 修饰静态方法:整个静态方法,作用于所有对象 修饰类:括号括...

    尚硅谷_互联网大厂高频重点面试题(第2季).xmind

    上半场,从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、线程池等重点;下半场,逐步过渡到JVM和GC的知识,深度讲解多种常见OOM异常和JVM参数调优,...

    2019年互联网大厂高频重点面试题第二季(思维导图+视频)

    尚硅谷2019年互联网...从多线程并发入手,分层递进讲解,逐步让大家掌握volatile、原子类和原子引用、CAS、ABA、Java锁机制、阻塞队列、线程池等重点,逐步过渡到JVM和GC的知识,深度讲解多种常见OOM异常和JVM参数调

    多核计算与程序设计(2009年3月1日出版)第四五部分

    本书是我从学校图书馆下的,出版时间: 2009-3-1。...最后一章中还介绍了Lock-Free编程(使用CAS原子操作进行编程)的基础知识,如ABA问题,内存删除问题等,并给出了一个Lock-Free的队列的实现实例。

    javabitset源码-Study:学习

    Java中的锁和同步类 公平锁 & 非公平锁 悲观锁 乐观锁 & CAS ABA 问题 CopyOnWrite容器 RingBuffer 可重入锁 & 不可重入锁 互斥锁 & 共享锁 死锁 操作系统 计算机原理 CPU 多级缓存 进程 线程 协程 Linux 设计模式 ...

    SAP R/3 事务码速查手册SAP R/3 事务码速查手册

    2.7.2 FI-SL-VSR 确认,替换和规则 69 2.7.3 FI-SL-IS 信息系统 69 2.8 FI-FM 基金管理 70 2.8.1 FI-FM-BD 基本数据 71 2.8.2 FI-FM-BU 预算 72 2.8.3 FI-FM-IN 集成 74 2.8.4 FI-FM-IS 信息系统 74 2.9 FI-TV 差旅...

Global site tag (gtag.js) - Google Analytics