java的原子类到底是啥?ABA,CAS又是些什么?
1)解决并发不是用锁就能解决吗,那SDK干嘛还要搞个原子类出来?
锁虽然能解决,但是加锁解锁始终还是对性能是有影响的,并且使用不当可能会造成死锁之类的问题。
2)原子类是怎样使用的,比如说我要实现一个线程安全的累加器?
public class Test {
AtomicLong count =
new AtomicLong(0); // 原子类变量count
void add10K() {
int idx = 0;
while(idx++ < 10000) {
count.getAndIncrement();// 原子操作
}
}
}
3)原子类是无锁的,那他底层是靠什么来实现原子安全的?
靠硬件。我们的CPU为了解决并发问题,提供了CAS指令,而CPU的指令本身就是原子性的。
4)什么是CAS呢?
compare and swap ,他主要就看3个参数,A是共享变量的内存地址,B是用于和原地址值比较的,C是我们要更新的值。
其实就是把原来的共享变量的值取出一份来,然后你要更新的话,得对比一下,当前的值和我取出来保存的这份值是不是相同的,如果是相同的,那就可以修改,不同的话说明被别人修改过了,那你现在就不能更新。
class SimulatedCAS{
int count;
synchronized int cas(
int expect, int newValue){
// 读目前count的值
int curValue = count;
// 比较目前count值是否==期望值
if(curValue == expect){
// 如果是,则更新count的值
count = newValue;
}
// 返回写入前的值
return curValue;
}
}
5)假如我当前的值和我取出来的那份值不一样了,那该怎么办?
CAS一般带有自旋,所谓自旋也就是循环的意思。当值不同了 ,那就从头来进行:取值来放着--->对比--->相同的话那就更新,不同就从头再来。
class SimulatedCAS{
volatile int count;
// 实现count+=1
addOne(){
do {
newValue = count+1; //①
}while(count !=
cas(count,newValue) //②
}
// 模拟实现CAS,仅用来帮助理解
synchronized int cas(
int expect, int newValue){
// 读目前count的值
int curValue = count;
// 比较目前count值是否==期望值
if(curValue == expect){
// 如果是,则更新count的值
count= newValue;
}
// 返回写入前的值
return curValue;
}
}
从上面代码我们也可以看出来,完全是没有加锁解锁的操作的,所以CAS这种无锁实现并发的操作性能很好。
6)我们说凡事都有两面性,CAS他就没任何的缺点吗?
会存在ABA问题,比如之前我取出来了一份值是A,但是在我进行对比之前,其它线程悄悄滴过来 ,把我的共享变量修改为了B,然后又修改成了A。虽然看到的都是A,其实这是被修改过的了。
7)两个数值反正都是相同的,不影响我的更新,那我还在乎ABA干嘛?
如果我们只是进行数值的原子递增之类的操作,那我们是不需要关心的。但是如果是对象呢,对象就比数值讲究多了,可能 A表面都是 一样的,但是属性是不一样的。
8)怎样解决ABA问题呢?
在使用 CAS 方案的时候,一定要先 check 一下。
9)前面我们使用原子类 AtomicLong 的 getAndIncrement() 方法替代了count += 1,从而实现了线程安全。原子类 AtomicLong 的 getAndIncrement() 方法内部就是基于 CAS 实现的,那 Java 是如何使用 CAS 来实现原子化的count += 1的?
Java 1.8 版本中,getAndIncrement() 方法会转调 unsafe.getAndAddLong() 方法。这里 this 和 valueOffset 两个参数可以唯一确定共享变量的内存地址。
final long getAndIncrement() {
return unsafe.getAndAddLong(
this, valueOffset, 1L);
}
10)unsafe.getAndAddLong() 方法的底层源码实现是怎样的?
该方法首先会在内存中读取共享变量的值
之后循环调用 compareAndSwapLong() 方法来尝试设置共享变量的值,直到成功为止。
compareAndSwapLong() 是一个 native 方法,只有当内存中共享变量的值等于 expected 时,才会将共享变量的值更新为 x,并且返回 true;否则返回 fasle。
public final long getAndAddLong(
Object o, long offset, long delta){
long v;
do {
// 读取内存中的值
v = getLongVolatile(o, offset);
} while (!compareAndSwapLong(
o, offset, v, v + delta));
return v;
}
//原子性地将变量更新为x
//条件是内存中的值等于expected
//更新成功则返回true
native boolean compareAndSwapLong(
Object o, long offset,
long expected,
long x);
11)SDK中提供了哪些原子类给我们使用?

使用提示:Java 提供的原子类能够解决一些简单的原子性问题,但是我们所有原子类的方法都是针对一个共享变量的,如果你需要解决多个变量的原子性问题,建议还是使用互斥锁方案。原子类虽好,但使用要非常小心。
java的原子类到底是啥?ABA,CAS又是些什么?的更多相关文章
- java 线程 原子类相关操作演示样例 thinking in java4 文件夹21.3.4
java 线程 原子类相关操作演示样例 package org.rui.thread.volatiles; import java.util.Timer; import java.util.Time ...
- Java并发—原子类,java.util.concurrent.atomic包(转载)
原子类 Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单.性能高效.线程安全地更新一个变量 ...
- java并发:原子类之AtomicLong
原子类之AtomicLong java线程中的操作,需要满足原子性.可见性等原则,比如i++这样的操作不具备原子性, A线程读取了i,另一个线程执行i++,A线程再执行i++就会引发线程安全问题 推荐 ...
- (转)Java atomic原子类的使用方法和原理(一)
在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...
- java的原子类 AtomicInteger 实现原理是什么?
采用硬件提供原子操作指令实现的,即CAS.每次调用都会先判断预期的值是否符合,才进行写操作,保证数据安全. CAS机制 CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换. ...
- Java - “JUC”原子类
根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类. 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: AtomicIn ...
- CAS 算法与 Java 原子类
乐观锁 一般而言,在并发情况下我们必须通过一定的手段来保证数据的准确性,如果没有做好并发控制,就可能导致脏读.幻读和不可重复度等一系列问题.乐观锁是人们为了应付并发问题而提出的一种思想,具体的实现则有 ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)
这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...
随机推荐
- LeetCode-075-颜色分类
颜色分类 题目描述:给定一个包含红色.白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色.白色.蓝色顺序排列. 此题中,我们使用整数 0. 1 和 2 分别表示 ...
- mysql什么时候会发生file sort
看了网上很多排名很靠前的博客,发现好多都讲错了!我开始按照博客来,没有怀疑,直到自己试了一下才发现是错的. file sort在面试中有时候会问到,这个其实挺能区分是不是真的了解order by的执行 ...
- Linux密码操作
CentOS7 利用Python程序生成sha512加密密码: [root@localhost ~]# python -c 'import crypt,getpass;pw="zxcvbnm ...
- Redis常用命令代码实例集合
//连接本地的 Redis 服务 $redis = new Redis(); $redis->connect('127.0.0.1', 6379); $redis->auth('12345 ...
- tp5(laravel7) ajax模型修改数据
① 设置ajax请求(10分) ② 后台更改数据值(10分) ③ 重新计算平均分(10分) ④ 无刷新更新评分结果(10分) 思路: 在详情页面中有一个评分的按钮,单击后进行修改数据,首先找见本条数据 ...
- 原生JS实现拼图游戏
最近无聊,练练原生JS:实现拼图游戏.两种玩法:第一种是单击元素进行交换位置:第二种是拖拽元素进行位置交换.首先需要上传图片并进行回显(需要用到FileReader):下面是部分截图: 可以自行设置切 ...
- BSOJ5086题解
题意略. 我们设 \([x^k]G_n(x)\) 代表深度为 \(n\) 的树,距离为 \(k\) 的点对数量,\([x^k]F_n(x)\) 为深度为 $ n $ 的树中,深度为 \(k\) 的节点 ...
- 字节跳动流式数据集成基于Flink Checkpoint两阶段提交的实践和优化
背景 字节跳动开发套件数据集成团队(DTS ,Data Transmission Service)在字节跳动内基于 Flink 实现了流批一体的数据集成服务.其中一个典型场景是 Kafka/ByteM ...
- 服务器中一个进程kill不掉,如何处理?
问题描述: 我们在服务器中有时候kill一个进程,会碰到死活杀不死的情况,那么有可能这个进程成为了一个僵尸进程,zombie状态.这种情况是这个进程释放了资源,但是没有得到父进程的确认. 可以使用命令 ...
- Java基础——final、static关键字
final关键字是最终的意思,可以修饰成员方法.成员变量.类 特点: 1.修饰方法:表示该方法是最终方法,不能被重写 2.修饰变量:表示变量是常量,不能再次被赋值 3.修饰类:表示类是最终类,不能被继 ...