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的并发性会增强。但是在并发性增强的同时也会伴随着一些缺陷。

  1. 循环时间长、CPU开销会增大。
  2. 只能保证一个共享变量的原子操作。
  3. 引出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底层原理的更多相关文章

  1. Java并发容器,底层原理深入分析

    ConcurrentHashMap ConcurrentHashMap底层具体实现 JDK 1.7底层实现 将数据分为一段一段的存储,然后给每一段数据配一把锁, 当一个线程占用锁访问其中一个段数据时, ...

  2. JAVA框架 Spring AOP底层原理

    一:AOP(Aspect Oriented Programming)面向切面编程. 底层实现原理是java的动态代理:1.jdk的动态代理.2.spring的cglib代理. jdk的动态代理需要被代 ...

  3. java面试-CAS底层原理

    一.CAS是什么? 比较并交换,它是一条CPU并发原语. CAS是一种无锁算法,CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什 ...

  4. Java中的CAS原理

    前言:在对AQS框架进行分析的过程中发现了很多CAS操作,因此有必要对CAS进行一个梳理,也便更清楚的了解其原理. 1.CAS是什么 CAS,是compare and swap的缩写,中文含义:比较交 ...

  5. Java中的CAS实现原理

    一.什么是CAS? 在计算机科学中,比较和交换(Conmpare And Swap)是用于实现多线程同步的原子指令. 它将内存位置的内容与给定值进行比较,只有在相同的情况下,将该内存位置的内容修改为新 ...

  6. CAS底层原理与ABA问题

    CAS定义 CAS(Compare And Swap)是一种无锁算法.CAS算法是乐观锁的一种实现.CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B.当预期值A和内存值V相同时,将内存值V修 ...

  7. Java并发/多线程-CAS原理分析

    目录 什么是CAS 并发安全问题 举一个典型的例子i++ 如何解决? 底层原理 CAS需要注意的问题 使用限制 ABA 问题 概念 解决方案 高竞争下的开销问题 什么是CAS CAS 即 compar ...

  8. Java并发--Java中的CAS操作和实现原理

    版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/CringKong/article/deta ...

  9. Java锁与CAS

    一.加锁与无锁CAS 在谈论无锁概念时,总会关联起乐观派与悲观派,对于乐观派而言,他们认为事情总会往好的方向发展,总是认为坏的情况发生的概率特别小,可以无所顾忌地做事,但对于悲观派而已,他们总会认为发 ...

  10. 《Java并发编程的艺术》Java并发机制的底层实现原理(二)

    Java并发机制的底层实现原理 1.volatile volatile相当于轻量级的synchronized,在并发编程中保证数据的可见性,使用 valotile 修饰的变量,其内存模型会增加一个 L ...

随机推荐

  1. linux系统的启动流程梳理

    1. 不同版本的linux系统的启动流程 1.1 centos6.x系统的启动流程 其详细启动步骤如下: 1)开机,BIOS自检,检查各个硬件是否正常 2)读取硬盘MBR信息,引导系统启动 3)加载g ...

  2. Java源码系列1——ArrayList

    本文简单介绍了 ArrayList,并对扩容,添加,删除操作的源代码做分析.能力有限,欢迎指正. ArrayList是什么? ArrayList 就是数组列表,主要用来装载数据.底层实现是数组 Obj ...

  3. webpack之打包分析以及prefetching和preloading

    打包分析: https://webpack.js.org/guides/code-splitting/#bundle-analysis        性能优化使用缓存是很有限的,现在更多的应该是再编写 ...

  4. 用pycharm自带的数据库创建项目00

    一.生成表格1.创建模型类(在 models.py文件中创建一个person类并且继承models.Models类) 2.生成表格(在项目目录下)(1)生成迁移文件:在pycharm下方的命令行Ter ...

  5. [20200129]子光标不共享BIND_EQUIV_FAILURE.txt

    [20200129]子光标不共享BIND_EQUIV_FAILURE.txt --//生产系统再次遇到大量BIND_EQUIV_FAILURE原因导致子光标的情况.我看了我以前测试遇到的情况.--// ...

  6. linux 内核模块开发相关的文章搜集和模块开发过程中的小技巧

    最近需要开发一些内核模块,进行探究linux内核的一些特征,现在把一些遇到的比较好的文章和知识点,进行简要记录和备忘: 内核模块开发相关链接: https://www.thegeekstuff.com ...

  7. python实现串口通讯小程序(GUI界面)

    python实现串口通讯小程序(GUI界面) 使用python实现串口通讯需要使用python的pyserial库来实现,这个库在安装python的时候没有自动进行安装,需要自己进行安装. 1.安装p ...

  8. opencv —— Sobel 一阶导数算子、Scharr 滤波器 一阶导数用于边缘检测

    sobel 算子的基本概念 sobel 算子是一个主要用于边缘检测的离散微分算子,它结合了高斯平滑和微分求导,用于计算图像灰度函数的近似梯度. 其基础来自于一个事实,即在边缘部分,像素值出现“跳跃”或 ...

  9. 两种从 TensorFlow 的 checkpoint生成 frozenpb 的方法

    1. 从 ckpt-.data,ckpt-.index 和 .meta 生成 frozenpb import os import tensorflow as tf from tensorflow.py ...

  10. Python小白

      .IDLE软件为内建于CPython的集成开发环境(IDE),包括编辑器,编译或解释器,调试器       .py(后缀保存) 2.行一,单行注释     多行,”””    ‘’’  之后,内建 ...