AtomicStampedReference解决ABA问题
在运用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问题的更多相关文章
- 用AtomicStampedReference解决ABA问题
在运用CAS做Lock-Free操作中有一个经典的ABA问题: 线程1准备用CAS将变量的值由A替换为B,在此之前,线程2将变量的值由A替换为C,又由C替换为A,然后线程1执行CAS时发现变量的值仍然 ...
- CAS如何解决ABA问题
点赞再看,养成习惯,微信搜索「小大白日志」关注这个搬砖人. 文章不定期同步公众号,还有各种一线大厂面试原题.我的学习系列笔记. CAS如何解决ABA问题 什么是ABA:在CAS过程中,线程1.线程2分 ...
- 并发中的Native方法,CAS操作与ABA问题
Native方法,Unsafe与CAS操作 >>JNI和Native方法 Java中,通过JNI(Java Native Interface,java本地接口)来实现本地化,访问操作系统底 ...
- Java CAS 和ABA问题
独占锁:是一种悲观锁,synchronized就是一种独占锁,会导致其它所有需要锁的线程挂起,等待持有锁的线程释放锁. 乐观锁:每次不加锁,假设没有冲突去完成某项操作,如果因为冲突失败就重试,直到成功 ...
- 多线程同步工具——CAS原子变量
这是我参考的一篇文章<基于CAS的乐观锁实现>,讲述的是一种需要CPU支持的执行技术CAS(Compare and Swap). 首先理解什么是原子性操作,意思是不能再拆分的操作,例如改写 ...
- JUC学习笔记--Atomic原子类
J.U.C 框架学习顺序 http://blog.csdn.net/chen7253886/article/details/52769111 Atomic 原子操作类包 Atomic包 主要是在多线程 ...
- J.U.C CAS
在JDK1.5之前,也就是J.U.C加入JDK之前,Java是依靠synchronized关键字(JVM底层提供)来维护协调对共享字段的访问,保证对这些变量的独占访问权,并且以后其他线程忽的该锁时,将 ...
- 并发-AtomicInteger源码分析—基于CAS的乐观锁实现
AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...
- ReentrantLock 如何实现非公平锁?和公平锁实现有什么区别
reentrant 英[riːˈɛntrənt] 美[ˌriˈɛntrənt] 先学会读.单词原意是可重入的 考察显示锁的使用.可延伸知识点 独占锁 & 共享锁 独占锁 - 悲观锁(不能同时被 ...
随机推荐
- QQ 聊天机器人小薇 1.0.1 发布!
本次发布主要解决了消息丢失(Api返回码[1202])问题,并改进了改进了一些细节. 简介 XiaoV(小薇)是一个用 Java 写的 QQ 聊天机器人 Web 服务,可以用于社群互动: 监听多个 Q ...
- Java从入门到精通——数据库篇Mongo DB 导出,导入,备份
一.概述 本篇博客为大家讲述一下Mongo DB是如何导入导出数据,还有就是备份数据的. 在下面操作的时候需要把Mongo DB的服务端打开才能操作. 二.导出. MongoDB的导 ...
- android popupwindow位置显示
1.在控件的上方: private void showPopUp(View v) { LinearLayout layout = new LinearLayout(this); layout.setB ...
- 树莓派搭建web服务器(详细且良心)
安装Apache Apache服务器可以从Debian的源中下载.可以用apt下载. 首先要更新apt的软件列表.如果不运行sudo apt-get updata的话,apt软件就不知道有没有新的软件 ...
- Github上600多个iOS开源项目地址
将Github上600多个iOS开源项目进行分类并且有相应介绍,小伙伴们快来看呀 地址:http://github.ibireme.com/github/list/ios/
- Jenkins 修改主目录正解 workspace
方法一: 停止Jenkins服务 net stop Jenkins 找到Jenkins安装目录,Config.config文件,找到WorkSpaceDir配置,修改为目标地址,保存. 启用Jenki ...
- Android学习——自定义控件(一)
由于之前在实习生面试的时候,被面试官问到有关自定义控件的问题,但没有回答上来,于是回来后便学习了关于自定义控件的相关知识. 自定义控件介绍 自定义控件,按我的理解,大体上分为两种.一种是自己绘图或者加 ...
- Installing TensorFlow on Ubuntu
1.安装方法有4种,官方推荐是第一种. virtualenv(官方推荐) "native" pip Docker Anaconda 2.基于virtualenv的 ...
- mongoDb 命令
1.显示MongoDB的服务器统计:db.stats() 2.创建数据库:use dbname 3.删除数据库:db.dropDatabase() 4.检查当前选择的数据库:db 5.检查数据库列表: ...
- Python初学者第八天 元组和字典
8day 1.数据类型:元组 元组:有序的,不可变地数据的集合.但若包含其他可变元素,这些元素可变.显示的告诉别人,此处不可修改: a = (1,2,3,4,5,['1','a']) 2.数据类型:字 ...