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

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

 

 

在运用CAS做Lock-Free操作中有一个经典的ABA问题:

线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然为A,所以CAS成功。

但实际上这时的现场已经和最初不同了,尽管CAS成功,但可能存在潜藏的问题,例如下面的例子:

以上就是由于ABA问题带来的隐患,各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题。

在Java中,AtomicStampedReference<E>也实现了这个作用,它通过包装[E,Integer]的元组来对对象标记版本戳stamp,从而避免ABA问题。

例如下面的代码分别用AtomicInteger和AtomicStampedReference来对初始值为100的原子整型变量进行更新,AtomicInteger会成功执行CAS操作,而加上版本戳的AtomicStampedReference对于ABA问题会执行CAS失败:

package com.vatuse.thread;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.atomic.AtomicStampedReference;public class ABATest {    private static AtomicInteger atomicInt = new AtomicInteger(100);    private static AtomicStampedReference
atomicStampedRef = new AtomicStampedReference
(100, 0); public static void main(String[] args) throws InterruptedException { Thread intT1 = new Thread(new Runnable() { @Override public void run() { atomicInt.compareAndSet(100, 101); atomicInt.compareAndSet(101, 100); } }); Thread intT2 = new Thread(new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } boolean c3 = atomicInt.compareAndSet(100, 101); System.out.println(c3); // true } }); intT1.start(); intT2.start(); intT1.join(); intT2.join(); Thread refT1 = new Thread(new Runnable() { @Override public void run(){ try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } atomicStampedRef.compareAndSet(100, 101, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1); atomicStampedRef.compareAndSet(101, 100, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1); } }); Thread refT2 = new Thread(new Runnable() { @Override public void run() { int stamp = atomicStampedRef.getStamp(); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { } boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1); System.out.println(c3); // false } }); refT1.start(); refT2.start(); }}
备注:AtomicStampedReference源代码里使用的是CopyOnWrite的策略来保证线程安全,更改前保持pair的应用,每次更改都会新生成一个pair。
AtomicMarkableReference也能达到类似的效果。

转载于:https://www.cnblogs.com/zyy1688/p/10655485.html

你可能感兴趣的文章
Python Django 之 登录页面
查看>>
iOS UILabel设置居上对齐,居中对齐,居下对齐
查看>>
C语言之函数调用17—递归法之中的一个般函数的调用(2)
查看>>
关于win7下的iis的一些问题
查看>>
最长公共子串-golang
查看>>
Mycat入门配置_读写分离配置
查看>>
Delphi Memo中禁止汉字
查看>>
我的第一篇博客
查看>>
小属性
查看>>
https://doc.opensuse.org/projects/kiwi/doc/
查看>>
大话无线通信
查看>>
XSLT+XML导出EXCEL,如何设定打印区域(以行数与列数)大小?
查看>>
我第一个篇随笔
查看>>
9.6、魔法常量
查看>>
table的拖拽选中区域(包含行合并和列合并的处理)
查看>>
TCP连接探测中的Keepalive和心跳包. 关键字: tcp keepalive, 心跳, 保活
查看>>
安装Tomcat指定JDK(转)
查看>>
Netflix
查看>>
使用Mybatis-Generator自动生成Dao、Model、Mapping相关文件(转)
查看>>
你真的了解try{ return }finally{}中的return?(转)
查看>>