点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人。

文章不定期同步公众号,还有各种一线大厂面试原题、我的学习系列笔记。

CAS如何解决ABA问题

什么是ABA:在CAS过程中,线程1、线程2分别从内存中拿到了当前值为A,同时线程2把当前值A改为B,随后又把B改回来变为A,此后线程1检查到当前值仍为A而导致执行cas成功,但这个过程却发生了ABA问题,现场资源可能和当初不一样了(线程2把当前值由A->B->A)

解决方法:版本号机制,利用版本号标记线程1拿到的‘当前值’的版本,若线程2进行了A->B->A操作,则版本号会改变,那线程1再次拿到的‘当前值’的版本和第一次的肯定是不同的,从而判定cas失败;

java代码中AtomicStampedReference类的cas方法实现了版本号机制,可用它来解决ABA问题:

/**
* @Description 测试解决CAS中的ABA问题
* @Author afei
* @date:2021/6/27
*/
public class AtomicStampedReferenceTest {
//AtomicInteger和AtomicStampedReference的初始值都为100,但AtomicStampedReference带了版本号0
private static AtomicInteger atomicInt = new AtomicInteger(100);
private static AtomicStampedReference atomicStampedRef = new AtomicStampedReference(100, 0);
public static void main(String[] args) {
//用AtomicInteger会产生ABA问题
aba1();
//用AtomicStampedReference解决cas过程中的ABA问题
aba2();
} public static void aba1(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
boolean c3 = atomicInt.compareAndSet(100, 101);
System.out.println(c3); // true
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
//t2改变100->101->100,compareAndSet的参数:期待的值,新值
atomicInt.compareAndSet(100, 101);
atomicInt.compareAndSet(101, 100);
}
});
t1.start();
t2.start();
try {
//t1,t2执行完,主线程才能继续执行
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void aba2(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
int stamp = atomicStampedRef.getStamp();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
}
//compareAndSet中四个参数分别为:期待的值,新值,期待的版本号,新的版本号
boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);
System.out.println(c3); // false
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run(){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
//t2改变100->101->100,compareAndSet中四个参数分别为:期待的值,新值,期待的版本号,新的版本号
atomicStampedRef.compareAndSet(100, 101, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
atomicStampedRef.compareAndSet(101, 100, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
}
});
t1.start();
t2.start();
}
}

AtomicInteger的原理

Java可以利用Syschronized、ReentrantLock、AtomicInteger类实现线程安全,AtomicInteger封装了一个【volatile int value】属性,它可以对这个属性进行许多原子性操作,这些原子性操作大多是基于cas原理,而在cas中,AtomicInteger使用的是一个叫Unsafe的类中的方法,Unsafe可以提供一些底层操作,也就是CPU特定的指令集,进而避免了并发问题(Unsafe是一个很危险的类,它可以做一些和内存相关的操作)

OK,如果文章哪里有错误或不足,欢迎各位留言。

创作不易,各位的「三连」是二少创作的最大动力!我们下期见!

CAS如何解决ABA问题的更多相关文章

  1. CAS导致的ABA问题及解决:时间戳原子引用AtomicReference、AtomicStampedReference

    1.CAS导致ABA问题: CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并交换,那么在这个时间差中会导致数据的变化. 比如:线程1从内存位置V中取出A,这时线程2也从V中取出A ...

  2. JUC 并发编程--05, Volatile关键字特性: 可见性, 不保证原子性,禁止指令重排, 代码证明过程. CAS了解么 , ABA怎么解决, 手写自旋锁和死锁

    问: 了解volatile关键字么? 答: 他是java 的关键字, 保证可见性, 不保证原子性, 禁止指令重排 问: 你说的这三个特性, 能写代码证明么? 答: .... 问: 听说过 CAS么 他 ...

  3. AtomicStampedReference AtomicReference解决CAS机制中ABA问题

    AtomicStampedReference AtomicReference解决CAS机制中ABA问题 AtomicStampedReference AtomicStampedReference它内部 ...

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

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

  5. java并发:CAS算法和ABA问题

    CAS算法是硬件对于并发的支持,针对多处理器操作而设计的处理器中的一种特殊指令. CAS用于管理对共享数据的并发访问. java的并发包中,AQS.原子操作类等都是基于CAS实现的. CAS 是一种 ...

  6. 基于CAS分析对ABA问题的一点思考

    基于CAS分析对ABA问题的一点思考 什么是CAS? 背景 synchronized加锁消耗太大 volatile只保证可见性,不保证原子性 基础 用CPU提供的特殊指令,可以: 自动更新共享数据; ...

  7. 高并发之CAS机制和ABA问题

    什么是CAS机制 CAS是英文单词Compare and Swap的缩写,翻译过来就是比较并替换 CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B. 看如下几个例子: pac ...

  8. 用CAS方案解决高并发一致性问题

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt395 缘起:在高并发的分布式环境下,对于数据的查询与修改容易引发一致性问题, ...

  9. 用AtomicStampedReference解决ABA问题

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

随机推荐

  1. EasyExcel完成excel文件的导入导出

    简介 常见的Excel分析框架有Apache poi 和EasyExcel, poi在另一篇已经介绍过了,详情可以看[https://www.cnblogs.com/jasmine-e/p/16064 ...

  2. Java基础(中)

    面向对象基础 面向对象和面向过程的区别 两者的主要区别在于解决问题的方式不同: 面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题. 面向对象会先抽象出对象,然后用对象执行方法的方式 ...

  3. python3 爬虫3--异常处理

    本文学习内容来自:https://germey.gitbooks.io/python3webspider/content/ urllib库中有URLError类,request模块产生的错误都可以通过 ...

  4. linklist template

    #include <iostream.h> typedef int ElemType; typedef struct LNode { ElemType data; struct LNode ...

  5. 接口是否可继承(extends)接口?抽象类是否可实现(implements)接口?抽象类是否可继承具体类(concrete class)?

    接口可以继承接口,而且支持多重继承.抽象类可以实现(implements)接口,抽象类可继承具体类也可以继承抽象类.

  6. mysql问题排查与性能优化

     MySQL 问题排查都有哪些手段? 使用 show processlist 命令查看当前所有连接信息. 使用 explain 命令查询 SQL 语句执行计划. 开启慢查询日志,查看慢查询的 SQL. ...

  7. Java中如何声明方法?JavaScript中如何声明函数?

    public void method(){ } //实例方法 Function Declaration 可以定义命名的函数变量,而无需给变量赋值.Function Declaration 是一种独立的 ...

  8. 简述 Mybatis 的插件运行原理,以及如何编写一个插件。

    Mybatis 仅可以编写针对 ParameterHandler.ResultSetHandler. StatementHandler.Executor 这 4 种接口的插件,Mybatis 使用 J ...

  9. ThreadLocal是什么?使用场景有哪些?

    什么是ThreadLocal? ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本. 测试代码: package ...

  10. JVM监控工具介绍jstack, jconsole, jinfo, jmap, jdb, jsta

    JVM监控工具介绍 jstack - 如果java程序崩溃生成core文件,jstack工具可以用来获得core文件的java stack和native stack的信息,从而可以轻松地知道java程 ...