博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CAS和ABA问题
阅读量:7306 次
发布时间:2019-06-30

本文共 3234 字,大约阅读时间需要 10 分钟。

hot3.png

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 something6 7 // CAS,这时候会出现ABA问题,a指向的对象可能已经变了8 9 ref.compareAndSet(a, b)
复制代码

   

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

   

复制代码
// 用int做时间戳AtomicStampedReference
tail = new AtomicStampedReference
(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
{ 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
Pair
of(T reference, int stamp) {16 17 return new Pair
(reference, stamp);18 19 }20 21 }22 23 24 25 private volatile Pair
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
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
current = pair;56 57 return58 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
cmp, Pair
val) {82 83 return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);84 85 }
 
http://www.cnblogs.com/exceptioneye/p/5373498.html

转载于:https://my.oschina.net/xiaominmin/blog/1597807

你可能感兴趣的文章
使用 ipmitool 实现 Linux 系统下对服务器的BMC管理
查看>>
我的友情链接
查看>>
记一次800多万XML文本文件预处理经历
查看>>
redis3.2装完后 其它机子访问爆protocol error, got 'n' as reply type byte
查看>>
Linux文件系统权限第一弹:文件系统普通权限
查看>>
jQuery操作checkbox选择代码
查看>>
从Facebook手机窥视Facebook发展计划
查看>>
ubuntu时间不对
查看>>
ctags: skipping ***: it is not a regular file.
查看>>
Application中调用getSharedPreferences()出现空指针异常
查看>>
Synchronized关键字
查看>>
演示:思科路由器上DHCP帮助地址的配置
查看>>
We7——很有意思的一个开源CMS
查看>>
多线程
查看>>
webpack使用(一)
查看>>
×××---虚拟专用网服务器
查看>>
解读百度的网站收录和网站清除规则转载
查看>>
详解HttpURLConnection
查看>>
Spring 框架的设计理念与设计模式分析
查看>>
linux查看内存、cpu命令
查看>>