java - CAS及CAS底层原理
CAS是什么?
CAS的全称为Compare-And-Swap它是一条CPU并发原语,也就是在CPU硬件层面上来说比较并且判断是否设置新值这段操作是原子性的,不会被其他线程所打断。在JAVA并发包java.util.concurrent.atomic下底层所采用的就是利用CAS机制来避免进行并发计算时导致数据错乱问题。
atomic底层实现
java.util.concurrent.atomic下各个类主要使用UnSafe类来进行Compare-And-Swap操作。
Unsafe是Java中一个底层类,包含了很多基础的操作,比如数组操作、对象操作、内存操作、CAS操作、线程(park)操作、栅栏(Fence)操作,JUC包、一些三方框架都使用Unsafe类来保证并发安全。Unsafe类在jdk 源码的多个类中用到,这个类的提供了一些绕开JVM的更底层功能,基于它的实现可以提高效率。但是,它是一把双刃剑:正如它的名字所预示的那样,它是Unsafe的,它所分配的内存需要手动free(不被GC回收)。Unsafe类,提供了JNI某些功能的简单替代:确保高效性的同时,使事情变得更简单。
如果需要自定义原子引用则可以通过类AtomicReference通过泛型设置,本篇不做过多介绍。
接下来以AtomicInteger类为切入点来看看Atomic是如何利用Compare-And-Swap来保证并发安全。
public class AtomicInteger extends Number implements java.io.Serializable {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
//1.objectFieldOffset()方法用于获取某个字段相对Java对象的起始地址的偏移量。
//2.下次访问将直接通过this对象与相对偏移量直接从内存访问value的值。从不经过JVM虚拟机。
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
private volatile int value;
.
.
.
//调用unsafe对预期值进行判断,如果判断成功则将值设置进去。
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//调用unsafe.getAndAddInt方法,该方法内部采用自旋锁不断compareAndSet当设置成功后才跳循环,否则不断得查询并且计算然后进行compareAndSet。
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
public final class Unsafe {
.
.
.
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public native int getIntVolatile(Object var1, long var2);
//通过一个死循环不停的获取值并且计算然后比较是否能够设置否则继续如此操作。
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
//compareAndSwapInt是Unsafe类利用计算机底层实现的,该操作是具有原子性,所以不必担心并发问题。
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
}
CAS的缺点
因为CAS并不像synchronized锁住整个方法,其他线程会处于等待锁释放状态。所以CAS的并发性会增强。但是在并发性增强的同时也会伴随着一些缺陷。
- 循环时间长、CPU开销会增大。
- 只能保证一个共享变量的原子操作。
- 引出ABA问题。
ABA问题
假设有这么一个变量a其初始值为1,两个线程分别为线程A与线程B,线程A的调用周期远低于线程B。
顺序 | 线程A | 线程B |
---|---|---|
1 | a=getIntVolatile(0) | |
2 | a=getIntVolatile(0) | |
3 | this.compareAndSwapInt(var1, var2, a, 1) | |
4 | a=getIntVolatile(1) | |
5 | this.compareAndSwapInt(var1, var2, a, 0) | |
6 | this.compareAndSwapInt(var1, var2, a, 2) |
对于线程B是能够compareAndSwapInt成功的他无法感知到线程A将a变量设置为1后又设置为0的过程,线程B只关注结果,只要在执行compareAndSwapInt的时候预期值符合就能够将值设置进去。
ABA问题解决
解决ABA问题的其中思路就是引入版本号控制。对于每个compareAndSet成功的则版本号进行加1,然后每次拿着这个版本号去做期望值匹配,这样就能够避免ABA问题。所幸在java.util.concurrent.atomic包下同样有为我们提供已版本号为基础的原子引用操作类AtomicStampedReference。
//创建出AtomicStampedReference实例,参数分别为初始值和初始版本号
AtomicStampedReference<Integer> atomicStampedReference=new AtomicStampedReference(100,1);
//获取当前版本号
int stamp=atomicStampedReference.getStamp();
//执行比较并且设置参数分别为期望值,设置新值,期望版本号,设置新版本号
atomicStampedReference.compareAndSet(100,200,stamp,stamp+1)
java - CAS及CAS底层原理的更多相关文章
- Java并发容器,底层原理深入分析
ConcurrentHashMap ConcurrentHashMap底层具体实现 JDK 1.7底层实现 将数据分为一段一段的存储,然后给每一段数据配一把锁, 当一个线程占用锁访问其中一个段数据时, ...
- JAVA框架 Spring AOP底层原理
一:AOP(Aspect Oriented Programming)面向切面编程. 底层实现原理是java的动态代理:1.jdk的动态代理.2.spring的cglib代理. jdk的动态代理需要被代 ...
- java面试-CAS底层原理
一.CAS是什么? 比较并交换,它是一条CPU并发原语. CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什 ...
- Java中的CAS原理
前言:在对AQS框架进行分析的过程中发现了很多CAS操作,因此有必要对CAS进行一个梳理,也便更清楚的了解其原理. 1.CAS是什么 CAS,是compare and swap的缩写,中文含义:比较交 ...
- Java中的CAS实现原理
一.什么是CAS? 在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令. 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新 ...
- CAS底层原理与ABA问题
CAS定义 CAS(Compare And Swap)是一种无锁算法.CAS算法是乐观锁的一种实现.CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当预期值A和内存值V相同时,将内存值V修 ...
- Java并发/多线程-CAS原理分析
目录 什么是CAS 并发安全问题 举一个典型的例子i++ 如何解决? 底层原理 CAS需要注意的问题 使用限制 ABA 问题 概念 解决方案 高竞争下的开销问题 什么是CAS CAS 即 compar ...
- Java并发--Java中的CAS操作和实现原理
版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/CringKong/article/deta ...
- Java锁与CAS
一.加锁与无锁CAS 在谈论无锁概念时,总会关联起乐观派与悲观派,对于乐观派而言,他们认为事情总会往好的方向发展,总是认为坏的情况发生的概率特别小,可以无所顾忌地做事,但对于悲观派而已,他们总会认为发 ...
- 《Java并发编程的艺术》Java并发机制的底层实现原理(二)
Java并发机制的底层实现原理 1.volatile volatile相当于轻量级的synchronized,在并发编程中保证数据的可见性,使用 valotile 修饰的变量,其内存模型会增加一个 L ...
随机推荐
- matplotlib如何画子图
目录 前言 常用的两种方式 方式一:通过plt的subplot 方式二:通过figure的add_subplot 方式三:通过plt的subplots 如何不规则划分 前言 Matplotlib的可以 ...
- 作为一个Java工程师,你应该要知道SPI机制
什么是 SPI SPI是Service Provider Interface的简称,是JDK默认提供的一种将接口和实现类进行分离的机制.这种机制能将接口和实现进行解耦,大大提升系统的可扩展性. SPI ...
- js , forEach 用法
person.forEach((item,index) => { console.log( item.id ); if( id == item.id ){ item.is_selected = ...
- 题解【[USACO05NOV]奶牛玩杂技】
\[ \texttt{Description} \] 有 \(n\) 头牛,每头牛都有自己的体重 \(W_i\) 和力量 \(S_i\) . 将这 \(n\) 头牛摞在一起,每头牛的压扁指数定义为:压 ...
- MySql优化之mycat
1. 解压mycat,不要放在有中文目录的地方 下载地址:http://dl.mycat.io/1.6-RELEASE/2 .修改mycat解压目录下的conf文件夹中server.xml文件,配置 ...
- 选择排序 C++实现
实现思想: 1.寻找[i, n)区间里的最小值min ( i>= 0 ) 2.交换min和第i的数 ( i>= 0 ) #include <iostream> #include ...
- MongoDB3.6版本新增特性
MongoDB3.6版新特性如下: (1)Default Bind to Localhost 从3.6版本开始,在默认情况下,MongoDB二进制文件mongod和mongos绑定到localhost ...
- postman界面按钮
Inport:导入,直接导入postman请求集或请求文件 Runner: 执行请求,选择执行请求的collection,并且添加执行参数,例如执行时间,执行次数 History: 所有调试的历史请求 ...
- VM虚拟机扩展Ubuntu磁盘空间
VM虚拟机扩展Ubuntu磁盘空间 1 环境 VMware版本号:15.0.2 build-10952284 系统:Ubuntu18.04 Ubuntu只挂载一个硬盘,无分区 /dev/sda1 2 ...
- Document节点
概述 document节点对象代表整个文档,每张网页都有自己的document对象.window.document属性就指向这个对象.只要浏览器开始载入 HTML 文档,该对象就存在了,可以直接使用. ...