JUC包-原子类(AtomicInteger为例)
JUC包-原子类
为什么需要JUC包中的原子类
首先,一个简单的i++可以分为三步:
读取i的值
计算i+1
将计算出i+1赋给i
这就无法保证i++的原子性,即在i++过程中,可能会出现其他线程也读取了i的
值,但读取到的不是更改过后的i的值。
原子类原理(AtomicInteger为例)
原子类的原子性是通过volatile + CAS实现原子操作的。
volatile

AtomicInteger类中的value是有volatile关键字修饰的,这就保证了value的内存可见性,这为后续的CAS实现提供了基础。
CAS
通过查看源码可以发现,AtomicInteger类的值更新操作都是通过调用
getAndAddInt(Object var1, long var2, int var4)方法实现
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
//返回的是修改前的值,类似于i++
return unsafe.getAndAddInt(this, valueOffset, delta);
}
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the updated value
*/
public final int addAndGet(int delta) {
//返回的是更新后的值,类似于++i
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
当我们查看getAndAddInt方法的具体实现,可以发现在整个方法中存在一个循
环,这就是我们说的自旋锁,顾名思义,while语句里面的条件一直为true,这个
循环就会一直执行下去。
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
下面我们来分析getAndAddInt方法中的各个参数的具体含义:
Object var1:this,表示当前对象
long var2:valueOffset,表示当前对象的内存偏移量
int var4:delat,需要加上的数值
所以整个方法的运行流程可以归纳为:
读取传入对象this在主存中偏移量为offset位置的值赋值给var5
将var5的值与当前线程对象内存中偏移量为offset位置的值进行比较(compare)
如果相等,将var5+var4的值更新到对象内存中偏移量为offset位置(swap);如果不
相等,就进入while循环自旋。
CAS的缺点
循环时间长,开销大
在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却
又一直更新不成功,循环往复,会给CPU带来很大的压力
只能保证一个共享变量的原子性操作
CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块
的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用
Synchronized了
ABA问题
见下文
ABA问题
什么是ABA问题
简单来说就是CAS过程只在乎当前值与期望值是否相等,只在乎最终结果,不考虑中
间变化,具体可以看下面一个简单的例子。
public class Test {
static AtomicInteger atomicInteger = new AtomicInteger(0);
public static void main(String[] args) {
atomicInteger.compareAndSet(0,1);
System.out.println("线程A第一次修改:0->" + atomicInteger.get());
new Thread(() -> {
atomicInteger.compareAndSet(1,0);
System.out.println("线程A第二次修改:1->" + atomicInteger.get());
}, "testA").start();
new Thread(() -> {
try {
//确保A线程修改完毕
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicInteger.compareAndSet(0,2);
System.out.println("线程B第一次修改:0->" + atomicInteger.get());
}, "testB").start();
}
}
程序运行后输出的结果,由此可见AtomicInteger的CAS中间步骤有变化,但是没有被感知到。

ABA问题的解决办法
一个简单的想法是,在数据上加上时间戳(版本号),使得线程每次对变量进行修改时,不仅要对比值,还要
对比时间戳(版本号),每次修改操作都会导致时间戳(版本号)改变为新的
值;
我们通过AtomicStampedReference类引入版本号,如下图所示
public class Test {
//初始化数值为0,版本号为1
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(0, 1);
public static void main(String[] args) {
new Thread(() -> {
/* compareAndSet四个参数分别为
* 期望值/新的值/期望版本号/新的版本号
*/
atomicStampedReference.compareAndSet(0, 1, 1, 2);
System.out.println("数值第一次修改为" + atomicStampedReference.getReference() +
" 版本号第一次修改为" + atomicStampedReference.getStamp());
atomicStampedReference.compareAndSet(1, 0, 2, 3);
System.out.println("数值第二次修改为" + atomicStampedReference.getReference() +
" 版本号第二次修改为" + atomicStampedReference.getStamp());
}, "testA").start();
new Thread(() -> {
try {
//确保A线程修改完毕
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
atomicStampedReference.compareAndSet(0, 1, 1, 2);
System.out.println("数值第三次修改为" + atomicStampedReference.getReference() +
" 版本号第三次修改为" + atomicStampedReference.getStamp());
}, "testB").start();
}
}
上述代码的程序运行结果如下图所示,可以看到当第三次修改的时候,虽然期望值0匹配,但是期望版本号不匹配,导致第三次修改无效。

JUC包-原子类(AtomicInteger为例)的更多相关文章
- juc原子类之二:基本类型原子类AtomicInteger(AtomicLong、AtomicBoolean)
一.AtomicInteger简介 AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似.以AtomicInteger对基本类型的原子类 ...
- JUC之原子类
在分析原子类之前,先来了解CAS操作 CAS CAS,compare and swap的缩写,中文翻译成比较并交换. CAS 操作包含三个操作数 —— 内存位置(V).预期原值(A)和新值(B).如果 ...
- 对Java原子类AtomicInteger实现原理的一点总结
java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...
- Java原子类AtomicInteger实现原理的一点总结
java原子类不多,包路径位于:java.util.concurrent.atomic,大致有如下的类: java.util.concurrent.atomic.AtomicBoolean java. ...
- java的原子类 AtomicInteger 实现原理是什么?
采用硬件提供原子操作指令实现的,即CAS.每次调用都会先判断预期的值是否符合,才进行写操作,保证数据安全. CAS机制 CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换. ...
- CAS你知道吗?原子类AtomicInteger的ABA问题谈谈?
(1)CAS是什么? 比较并交换 举例1, CAS产生场景代码? import java.util.concurrent.atomic.AtomicInteger; public class CA ...
- 浅析CAS与AtomicInteger原子类
一:CAS简介 CAS:Compare And Swap(字面意思是比较与交换),JUC包中大量使用到了CAS,比如我们的atomic包下的原子类就是基于CAS来实现.区别于悲观锁synchroniz ...
- 从原子类和Unsafe来理解Java内存模型,AtomicInteger的incrementAndGet方法源码介绍,valueOffset偏移量的理解
众所周知,i++分为三步: 1. 读取i的值 2. 计算i+1 3. 将计算出i+1赋给i 可以使用锁来保持操作的原子性和变量可见性,用volatile保持值的可见性和操作顺序性: 从一个小例子引发的 ...
- JUC源码学习笔记4——原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法
JUC源码学习笔记4--原子类,CAS,Volatile内存屏障,缓存伪共享与UnSafe相关方法 volatile的原理和内存屏障参考<Java并发编程的艺术> 原子类源码基于JDK8 ...
随机推荐
- PyQt(Python+Qt)学习随笔:QAbstractItemView的verticalScrollMode和horizontalScrollMode属性
老猿Python博文目录 老猿Python博客地址 一.概述 verticalScrollMode和horizontalScrollMode属性用于控制视图如何在垂直方向和水平方向滚动内容.滚动可以按 ...
- PyQt(Python+Qt)学习随笔:Qt Designer中toolBar的toolButtonStyle属性
tooButtonStyle属性保存主工具栏按钮的样式设置,用来表示工具栏按钮的文字和图标怎么显示. 该属性的可设置值类型为枚举类型Qt.ToolButtonStyle,它包含如下值: 该属性的缺省值 ...
- PLSQL Developer 工具应用
用户scott使用: 解锁scott: 第一步:登陆管理员 SQL语句:Sqlplus sys/tiger as sysdba 第二步:解锁scott SQL语句:Alter user scott a ...
- 凌乱的与ctf无关的小知识点
(1)在网页中一般不要用记住密码.否则想要知道你的密码很简单. 例子:看样子很安全,别人无法通过这些来获得你的其他密码(尤其是想我这样密码强度不高的人),但是知道要修改前端的选项,你的密码就会被暴露. ...
- Python3安装且环境配置(三)
1.在Window 平台安装 Python3 以下为在 Window 平台上安装 Python3 的简单步骤: 打开WEB浏览器访问http://www.python.org/download/ 在下 ...
- 题解-[SDOI2014]数数
[SDOI2014]数数 这题的前置知识是AC自动机和dp,前置题目是 [JSOI2007]文本生成器,前置题目我写的题解 题解-[JSOI2007]文本生成器.我的讲解假设你做过上面那道题. 这题比 ...
- logging 用于便捷记录日志且线程安全的模块
import logging logging.basicConfig(filename='log.log', format='%(asctime)s - %(name)s - %(levelname) ...
- .net5+nacos+ocelot 配置中心和服务发现实现
最近一段时间 因公司业务需要,需要使用.net5做一套微服务的接口,使用nacos 做注册中心和配置中心,ocelot做网关. 因为ocelot 支持的是consol和eureka,如果使用nacos ...
- OpenShift添加应用健康检查功能
什么是健康检查? 对于部署成功的应用来说,通过访问接口.执行特定命令等方式判断应用是否存活.正常的方式称为健康检查. 在 OpenShift 或 Kubernetes 中,健康检查都有两个探针,分别是 ...
- PB级大规模Elasticsearch集群运维与调优实践【>>戳文章免费体验Elasticsearch服务30天】
[活动]Elasticsearch Service免费体验馆>> Elasticsearch Service自建迁移特惠政策>>Elasticsearch Service新用户 ...