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 ...
随机推荐
- mongoose报错:DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes instead.
mongoose报错:(node:15689) DeprecationWarning: collection.ensureIndex is deprecated. Use createIndexes ...
- 面试突击 | Redis 如何从海量数据中查询出某一个 Key?附视频
1 考察知识点 本题考察的知识点有以下几个: Keys 和 Scan 的区别 Keys 查询的缺点 Scan 如何使用? Scan 查询的特点 2 解答思路 Keys 查询存在的问题 Scan 的使用 ...
- Java Lamada
Collection: ->stream:返回一个以 colleciotn 元素为数据源的数据流. -->map: 入参 Function 对象,将此流中的元素依次作用于传入的 Funct ...
- .NET Core MVC下的TagHelper
.NET web开发者在开发过程中,一定都踩过的坑,明明修改了js文件,可是部署到生产环境,客户反馈说:“还是报错啊”..然后一脸懵逼的去服务器上看文件,确实已经更新了.有经验的coder可能就想到了 ...
- C#设计模式学习笔记:(12)代理模式
本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7814004.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲结构型设计模式的第七个模式,也是 ...
- 剑指offer-面试题63-股票的最大利润-数组
/* 题目: 给定一个股价序列,求一次交易的最大利润. */ #include<iostream> #include<vector> using namespace std; ...
- 《手把手教你构建自己的 Linux 系统》学习笔记(9)
目录 autoreconf 命令的作用是什么? aclocal automake -a autoconf 一条命令搞完三面三步 既然有其他的「编译控制软件」为何还是使用 make 来进行编译控制? M ...
- python进阶----深拷贝&浅拷贝
复制需要区分,,复制的是源文件的数据,还是指向源文件数据的地址 1.引用 b=a时,理解为b指向了a指向的数据,相当于引用复制 a=[1,2] b=a #验证复制的是数据还是地址 #1.查看ab的 ...
- python_函数笔记
第二章 函数编程 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 形参变量 只有在被调 ...
- day 8 函数编程_byets
定义 bytes类型是指一堆字节的集合,在python中以b开头的字符串都是bytes类型 b'\xe5\xb0\x8f\xe7\x8c\xbf\xe5\x9c\x88' #b开头的都代表是bytes ...