在运用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<Integer> atomicStampedRef = new AtomicStampedReference<Integer>(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也能达到类似的效果。

AtomicStampedReference解决ABA问题的更多相关文章

  1. 用AtomicStampedReference解决ABA问题

    在运用CAS做Lock-Free操作中有一个经典的ABA问题: 线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然 ...

  2. CAS如何解决ABA问题

    点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. CAS如何解决ABA问题 什么是ABA:在CAS过程中,线程1.线程2分 ...

  3. 并发中的Native方法,CAS操作与ABA问题

    Native方法,Unsafe与CAS操作 >>JNI和Native方法 Java中,通过JNI(Java Native Interface,java本地接口)来实现本地化,访问操作系统底 ...

  4. Java CAS 和ABA问题

    独占锁:是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁. 乐观锁:每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功 ...

  5. 多线程同步工具——CAS原子变量

    这是我参考的一篇文章<基于CAS的乐观锁实现>,讲述的是一种需要CPU支持的执行技术CAS(Compare and Swap). 首先理解什么是原子性操作,意思是不能再拆分的操作,例如改写 ...

  6. JUC学习笔记--Atomic原子类

    J.U.C 框架学习顺序 http://blog.csdn.net/chen7253886/article/details/52769111 Atomic 原子操作类包 Atomic包 主要是在多线程 ...

  7. J.U.C CAS

    在JDK1.5之前,也就是J.U.C加入JDK之前,Java是依靠synchronized关键字(JVM底层提供)来维护协调对共享字段的访问,保证对这些变量的独占访问权,并且以后其他线程忽的该锁时,将 ...

  8. 并发-AtomicInteger源码分析—基于CAS的乐观锁实现

    AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...

  9. ReentrantLock 如何实现非公平锁?和公平锁实现有什么区别

    reentrant 英[riːˈɛntrənt] 美[ˌriˈɛntrənt] 先学会读.单词原意是可重入的 考察显示锁的使用.可延伸知识点 独占锁 & 共享锁 独占锁 - 悲观锁(不能同时被 ...

随机推荐

  1. mui.ajax()和asp.net sql服务器数据交互【3】最终版

    1.前端页面 <header class="mui-bar mui-bar-nav"> <a class="mui-action-back mui-ic ...

  2. jQuery ajax调接口时跨域

    解决方法提炼 一.jsonp方法 在前端ajax配置jsonp参数,在后台配置jsonp设置,具体方法自行百度 二. 参考同源策略 把前端静态页面放在tomcat内webapp下,和后台文件同目录, ...

  3. Python基础-进程和线程

    一.进程和线程的概念 首先,引出“多任务”的概念:多任务处理是指用户可以在同一时间内运行多个应用程序,每个应用程序被称作一个任务.Linux.windows就是支持多任务的操作系统,比起单任务系统它的 ...

  4. android query 模糊查询

    package com.example.utils; import java.util.ArrayList; import android.content.ContentValues; import ...

  5. DBGridEh常用技巧

    一.增加多表头显示方式 DBGridEh1.UseMultiTitle:=True; //打开多标题显示方式 DBGridEh1.Columns[].Title.Caption:='员工编号'; // ...

  6. 修改虚拟机ip备份

    修改虚拟机ip 因为别人写的很好,在此备份一下.

  7. Kettle数据抽取解决方案

    一. Kettle介绍 1. Kettle简介 ETL即数据抽取(Extract).转换(Transform).装载(Load)的过程.Kettle的中文翻译为水壶.Kettle以元数据驱动的方式提供 ...

  8. gitattributes中的filter

    .gitattributes文件就是一个简单的text文本文件,它的作用是gives attributes to pathnames. 该文件中的一些配置可以为某些特定目录或者文件来设置,这样Git就 ...

  9. MYSQL连接相关参数和状态值详解

    针对mysql的连接参数和状态值,本文做些介绍和对比 一.MYSQL连接参数变量 1.常用连接数限制参数 show variables like '%connect%'; | max_connect_ ...

  10. XML布局之路

    XML布局存放在工程文件的res/layout目录下.安卓和PC端的界面布局有用到. 常用的布局方式,线性布局:LinearLayout 表格布局:TableLayout 帧布局  :FrameLay ...