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的使用非常简 ...
随机推荐
- 02_opencv_python_图像处理进阶
1 灰度图 import cv2 # opencv读取的格式是BGR import numpy as np import matplotlib.pyplot as plt # Matplotlib是 ...
- LeetCode-028-实现 strStr()
实现 strStr() 题目描述:实现 strStr() 函数. 给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下 ...
- LeetCode-073-矩阵置零
矩阵置零 题目描述:给定一个 m x n 的矩阵,如果一个元素为 0 ,则将其所在行和列的所有元素都设为 0 .请使用 原地 算法. 进阶: 一个直观的解决方案是使用 O(mn) 的额外空间,但这并不 ...
- 初探JVM字节码
作者: LemonNan 原文地址: https://juejin.im/post/6885658003811827725 代码地址: https://github.com/LemonLmNan/By ...
- 空间插值生物X适宜性分析
1 前言 这期博主将根据示例大概讲一下插值分析. 2 问题阐述 根据要求,完成以下操作: (1)请就以上条件确定此地区适合X的生活范围,并制作专题图.专题图内容要求以地形和水系作为背景,且给出适宜区域 ...
- kubernetes内yaml格式
yaml格式的pod定义文件完整内容: apiVersion: v1 #必选,版本号,例如v1 可通过 kubectl api-versions 获取 kind: Pod #必选,Pod metada ...
- 6月28日 Django form组件 和 modelform组件
Form介绍 我们之前在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来. 与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否 ...
- 6月26日 Django 中间件
前戏 我们在前面的课程中已经学会了给视图函数加装饰器来判断是用户是否登录,把没有登录的用户请求跳转到登录页面.我们通过给几个特定视图函数加装饰器实现了这个需求.但是以后添加的视图函数可能也需要加上装 ...
- STM32芯片去除读写保护 | 使用ST-Link Utility去除STM32芯片读写保护
1.使用ST-LINK V2下载器连接到STM32芯片, 点击Connect: 2.存在读保护: 3.修改选项字节(Option Bytes... ): 4.将读保护修改为Disabled. 5.打钩 ...
- 项目可以怎么规范Git commit ?
通常情况下,commit message应该清晰明了,说明本次提交的目的,具体做了什么操作.但是在日常开发中,大家的commit message都比较随意,中英文混合使用的情况有时候很常见,这就导致后 ...