ABA问题的产生及解决
什么是ABA问题
在CAS算法中,需要取出内存中某时刻的数据(由用户完成),在下一时刻比较并交换(CPU保证原子操作),这个时间差会导致数据的变化。
1、线程1从内存位置V中取出A
2、线程2从内存位置V中取出A
3、线程2进行了写操作,将B写入内存位置V
4、线程2将A再次写入内存位置V
5、线程1进行CAS操作,发现V中仍然是A,交换成功
尽管线程1的CAS操作成功,但线程1并不知道内存位置V的数据发生过改变
ABA问题本质:
根本在于CAS在修改变量的时候,无法记录变量的状态,比如是否修改过这个变量,修改的次数。
public class ABADemo {
private static AtomicReference<Integer> atomicReference = new AtomicReference<Integer>();
public static void main(String[] args) {
new Thread(() -> {
Integer a = atomicReference.get();
atomicReference.compareAndSet(a, );
atomicReference.compareAndSet(, a);
System.out.println("t1修改了atomicReference的值");
},"t1").start();
new Thread(() -> {
Integer b = atomicReference.get();
try {
Thread.sleep();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(atomicReference.compareAndSet(b, ) + "\t修改后的值:" + atomicReference.get());
},"t2").start();
}
}
ABA问题怎么解决
public class AtomicStampedReferenceTest {
private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<Integer>(,);
public static void main(String[] args) {
new Thread(() -> {
Integer stamp = atomicStampedReference.getStamp();
System.out.println("t1拿到的初始版本号:" + stamp);
//睡眠1秒,是为了让t2线程也拿到同样的初始版本号
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(, ,stamp,stamp+);
stamp = atomicStampedReference.getStamp();
atomicStampedReference.compareAndSet(, ,stamp,stamp+);
},"t1").start();
new Thread(() -> {
int stamp = atomicStampedReference.getStamp();
System.out.println("t2拿到的初始版本号:" + stamp);
//睡眠3秒,是为了让t1线程完成ABA操作
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("最新版本号:" + atomicStampedReference.getStamp());
System.out.println(atomicStampedReference.compareAndSet(, ,stamp,atomicStampedReference.getStamp() + ) + "\t当前 值:" + atomicStampedReference.getReference());
},"t2").start();
}
}
如果不关心引用变量更改了几次,只单纯的关心是否更改过,可以使用AtomicMarkableReference
public class ABADemo {
private static AtomicMarkableReference<Integer> atomicMarkableReference = new AtomicMarkableReference<Integer>(,false);
public static void main(String[] args) {
new Thread(() -> {
System.out.println("t1版本号是否被更改:" + atomicMarkableReference.isMarked());
//睡眠1秒,是为了让t2线程也拿到同样的初始版本号
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicMarkableReference.compareAndSet(, ,false,true);
},"t1").start();
new Thread(() -> {
boolean isMarked = atomicMarkableReference.isMarked();
System.out.println("t2版本号是否被更改:" + isMarked);
//睡眠3秒,是为了让t1线程执行
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("是否更改过:" + atomicMarkableReference.isMarked());
System.out.println(atomicMarkableReference.compareAndSet(, ,isMarked,true) + "\t当前 值:" + atomicMarkableReference.getReference());
},"t2").start();
}
}
ABA问题的产生及解决的更多相关文章
- CAS与ABA问题产生和优雅解决
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...
- CAS如何解决ABA问题
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. CAS如何解决ABA问题 什么是ABA:在CAS过程中,线程1.线程2分 ...
- ABA问题怎么解:AtomicStampedReference和AtomicMarkableReference
本博客系列是学习并发编程过程中的记录总结.由于文章比较多,写的时间也比较散,所以我整理了个目录贴(传送门),方便查阅. 并发编程系列博客传送门 并发编程的基石--CAS机制这篇文章中介绍到CAS机制有 ...
- CAS 和 ABA 问题
CAS简介 CAS 全称是 compare and swap,是一种用于在多线程环境下实现同步功能的机制. CAS 它是一条CPU并发原语.操作包含三个操作数 -- 内存位置.预期数值和新值.CAS ...
- 原子类的ABA问题
原子类AtomicInteger的ABA问题 连环套路 从AtomicInteger引出下面的问题 CAS -> Unsafe -> CAS底层思想 -> ABA -> 原子引 ...
- CAS底层原理与ABA问题
CAS定义 CAS(Compare And Swap)是一种无锁算法.CAS算法是乐观锁的一种实现.CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当预期值A和内存值V相同时,将内存值V修 ...
- Java多线程_CAS算法和ABA问题
CAS算法概述CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换.CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B. CAS指令执行时,当且仅当内存地址V ...
- JUC学习笔记--Atomic原子类
J.U.C 框架学习顺序 http://blog.csdn.net/chen7253886/article/details/52769111 Atomic 原子操作类包 Atomic包 主要是在多线程 ...
- 【Bugly干货】Android性能优化典范之多线程篇
本文涉及的内容有:多线程并发的性能问题,介绍了 AsyncTask,HandlerThread,IntentService 与 ThreadPool 分别适合的使用场景以及各自的使用注意事项,这是一篇 ...
随机推荐
- SQLi-LABS Page-2 (Adv Injections) Less23-Less26
Less-23 GET - Error based - strip comments http://10.10.202.112/sqli/Less-23?id=1' Warning: mysql_fe ...
- iOS处理含中文的请求链接
NSString *urlStr = @""; // 将中文URL进行转码 urlStr = [urlStr stringByAddingPercentEscapesUsingEn ...
- 实用的生成二维码API
推荐一个生成二维码的API网站: 中文 http://www.topscan.com 英文 https://api.qrserver.com/v1/create-qr-code/?size=150x1 ...
- GraphQL快速入门教程
摘要: 体验神奇的GraphQL! 原文:GraphQL 入门详解 作者:MudOnTire Fundebug经授权转载,版权归原作者所有. GraphQL简介 定义 一种用于API调用的数据查询语言 ...
- 为什么重复的GET请求变慢了?
最近在研究慢请求监控的问题,写了一个简单的测试代码:在网页端(index.html)通过fetch函数向服务端获取数据,然后打印请求耗时. function requestData() { let s ...
- jQuery的animate
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- 【微信小程序】开发实战 之 「视图层」WXML & WXSS 全解析
在<微信小程序开发实战 之 「配置项」与「逻辑层」>中我们详细阐述了小程序开发的程序和页面各配置项与逻辑层的基础知识.下面我们继续解析小程序开发框架中的「视图层」部分.学习完这两篇文章的基 ...
- 不知道多大的文件不要用cat查看!
今天长清女子学校的主任给我微信上发了一图片,说登录服务器的时候就查看了一个文件,结果服务器的风扇忽然变的特别响,系统慢了好多,让我看看是什么回事!我当时心里想,无缘无故怎么会这样,难不成是进病毒了?查 ...
- Springboot将数据存储到数据库当中
1.从前端获取数据,同时存储到use当中 public String login(HttpServletRequest request) { User user = new User(); user. ...
- Spring data redis的使用
Spring data redis的使用 一.Redis的安装和使用 Redis是用C语言开发的一个高性能键值对数据库,可用于数据缓存,主要用于处理大量数据的高访问负载. 下载地址:https://g ...