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 分别适合的使用场景以及各自的使用注意事项,这是一篇 ...
随机推荐
- 教你使用 Swoole-Tracker 秒级定位 PHP 卡死问题
PHPer 肯定收到过这样的投诉:小菊花一直在转!你们网站怎么这么卡!当我们线上业务遇到这种卡住(阻塞)的情况,大部分 PHPer 会两眼一抹黑,随后想起那句名言:性能瓶颈都在数据库然后把锅甩给DBA ...
- open*** 搭建
pptp 互联网上服务商给拦截.不稳定. opevpn 1.为了保证OpenVPN的安装,需要使用easy-rsa秘钥生成工具生成证书 [root@m01 ~]# yum install easy-r ...
- Java开发中对Redis的基本操作
Jedis操作redis指令 import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; impo ...
- React + Ts 实现三子棋小游戏
在这里阅读效果更佳 还记得当年和同桌在草稿纸上下三子棋的时光吗 今天我们就用代码来重温一下年少(假设你有react基础,没有也行,只要你会三大框架的任意一种,上手react不难) 游戏规则 双方各执一 ...
- swift(一)基础变量类型
import Foundation println("Hello, World!") /* int a; */ var a = //隐式类型转换 a = println(a) le ...
- 北京地铁出行线路规划系统项目总结(Java+Flask+Vue实现)
北京地铁出行线路规划系统项目总结 GitHub仓库地址:https://github.com/KeadinZhou/SE-Subway Demo地址:http://10.66.2.161:8080/ ...
- X264-视频帧的存取
X264的编码器结构体x264_t中的子结构体字段frames包含了4个临时视频帧序列空间:current.next.unused和reference,分别保存当前编码帧.将编码帧序列.未处理原始视频 ...
- 分分钟搞定Redis编译安装
1. 依赖包安装 yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc- ...
- 函数arguments讲解
// 总结:1- 函数内部有一个实参 arguments 可以获取所有的实参. //2- arguments是一个伪数组,如果要使用数组的方法, 将它转为真数组 // 3 ...
- python hash 哈希值
自增知识点 1,哈希 什么是可哈希(hashable)? 简要的说可哈希的数据类型,即不可变的数据结构(字符串str.元组tuple.对象集objects). 哈希有啥作用? 它是一个将大体量数据转化 ...