首页 > 其他分享 >CAS原理

CAS原理

时间:2022-12-25 22:14:01浏览次数:37  
标签:var5 CAS 版本号 int 线程 操作 原理

 

目录

  • CAS简介
  • CAS思路
  • CAS使用场景
  • CAS问题
  • 总结

CAS简介

CAS的英文全称是Compare-And-Swap,意思就是比较并交换,他是原子类的底层原理,同时也是乐观锁的原理,CAS的特点是避免使用互斥锁,当多个线程同时更新同一个变量时,只有一个线程可以更新成功,其他的线程都会更新失败,和同步互斥锁不同的是,更新失败的线程并不会被阻塞,而是被告知此次竞争失败,下次还可以继续竞争。

 

CAS思路

首先,在大多数处理器指令中,CAS操作是一条(而不是多条)cpu指令,正是这个原因,所以CAS相关的指令是具备原子性的,这个组合操作在执行期间不会被打断,这样就保证了并发安全。

CAS有三个操作值:内存值V,预期值A,要修改的值B,当且仅当预期值A等于当前内存值V的时候,才将内存值更新为B。

CAS操作描述

执行成功:

当执行CAS操作的时候,如果发现当前的内存值V正好是值A的话,那么CAS就会更新内存值V为B,通常A往往是之前读取到的内存值, B是在A的基础上计算而得到的。例图如下:

 

 

 

执行失败:

dangzhixingCAS操作的时候,如果发现当前的内存值V不是预期值A,那么说明内存值已经被其他线程执行过了,本次CAS就会失败,这样就可以避免多人同时修改出错。例图如下:

 

 

 

 

CAS使用场景

数据库

基于数据库我们可以实现利用version字段在数据库中实现乐观锁和CAS操作,在获取和修改数据都不需要加悲观锁,例如:

UPDATE TABLE SET name ='测试', version = 2 WHERE id=1 and vsersion =1

 


原子类

很多原子类中都用了CAS操作,例如AtomicInteger的getAndAdd(int data)方法,如下图:getAndAdd是AtomicInteger类中的方法,getAndAddInt是调用unsafe中的方法。

var5的赋值调用了 unsafe 的 getIntVolatile(var1, var2) 方法,这是一个native方法,作用是获取变量var1中偏移量var2出的值,这里传入的参数var1的值是对AtomicInteger对象的引用,var2就是AtomicInteger中存的数值的偏移量也就是value,所以得到的var5的值代表当前时刻下的原子类中存储的值。

public final int getAndAdd(int delta) { 
return unsafe.getAndAddInt(this, valueOffset, delta);
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
​

  

 

代码中compareAndSwapInt方法的五个参数分别代表var1:object,var2:offset,var5:expectedValue,var5+var4:newValue。

第一个参数objec就是要修改的对象,传入的是this,也就是AtomicInteger这个对象。

 

第二个参数offset代表偏移量,借助它可以获取到value的数值。

第三个参数expectedValue代表期望值,传入的就是刚才获取的var5。

第四个参数newValue代表就是要修改为的值,等于之前得到的数值var5加上var4,而var4就是我们之前传入的delta,delta就是我们希望原子类改变的数值,可以传入+1,-1。

所以 compareAndSwapInt 方法的作用就是,判断如果现在原子类里 value 的值和之前获取到的 var5 相等的话,那么就把计算出来的 var5 + var4 给更新上去,所以说这行代码就实现了 CAS 的过程。

CAS操作成功,就会退出这个 while 循环,但是也有可能操作失败。如果操作失败就意味着在获取到 var5 之后,并且在 CAS 操作之前,value 的数值已经发生变化了,证明有其他线程修改过这个变量。

Unsafe中的getAndAddInt 方法通过循环+CAS的方式来实现,在这个过程中,通过compareAndSwapInt方法来尝试更新value的值,如果更新失败就重新获取,然后再次尝试,知道成功。

 

CAS问题

ABA问题

首先什么是ABA问题?ABA问题就是比如刚开始读取到的备份是3,然后被其他线程修改几次后,最终结果还是3,那么CAS很可能识别不到数据发生变化了,那么CAS 就会认为变量的值在此期间没有发生过变化。所以CAS并不能检测出在此期间值是不是被修改过,他只能检查测出现在的值和最初的只是不是一样的,这样就会有极大的隐患。

 

解决办法:可以通过添加版本号等标志位来解决,我们在这个值之外,再添加一个版本号,那么这个值的变化路径就从A->B->A变成了A1->B2->A3,这样一来就可以通过对比版本号来判断值是否发生过变化。

 

在atomic包中提供了AtomicStampedReference这个类,它是专门解决ABA问题的,解决思路也正是利用版本号,AtomicStampedReference会维护一种类似<Object,int>的数据结构,其中的int就是用于计数的,也就是版本号,它可以对这个对象和int版本号同时进行原子更新,从而也就解决了ABA问题,所以我们判断值是否被修改过,就通过版本号是否变化为标准,即使值一样,版本号也不一样。

 

循环问题

就像刚才说的,CAS可能会失败,而且CAS往往是配合着循环来实现的,失败就会一直重试,如果在CAS操作中一直失败,或者长时间自旋不成功,那么循环时间长开销大,会给CPU带来很大的开销。

解决方法:可以使用自适应自旋锁解决这个问题。

 

操作范围不能灵活控制

只能保证一个共享变量而不是多个共享变量的原子操作,这个对象可能是AtomicInteger、AtomicLong、或者其他类型的,但是我们不能针对多个共享变量同时进行CAS操作。比如AtomicInteger都是每次只对一个变量进行原子控制。

解决方法:通过利用一个新的类,来整合刚才这一组共享变量,这个类中的多个成员变量就是刚才那个共享变量,然后再利用atomic包中的AtomicReference来把这个新对象整体进行CAS操作,这样就可以保证线程安全。

 

总结

好了,今天主要讲解了关于CAS的介绍和优缺点,以及CAS的使用场景,CAS作为很多乐观锁的底层知识相当重要,理解CAS相关知识对学习并发编程相关概念和技能都有很大帮助!

标签:var5,CAS,版本号,int,线程,操作,原理
From: https://www.cnblogs.com/shoshana-kong/p/17004691.html

相关文章

  • SAP UI5 应用里 FlexBox 控件的设计原理
    sap.m.FlexBox控件为flexibleboxlayout构建容器。VBox控件为垂直的框布局(verticalflexibleboxlayout)构建容器。VBox是一种使用的控件,因为它只是一个定制化的......
  • SIFT特征原理简析(HELU版)
    SIFT(Scale-InvariantFeatureTransform)是一种具有尺度不变性和光照不变性的特征描述子,也同时是一套特征提取的理论,首次由D.G.Lowe于2004年以《DistinctiveImageFeatu......
  • 【优化技术专题】「系统性能调优实战」终极关注应用系统性能调优及原理剖析(下册)
    前提介绍承接上文:【优化技术专题】「系统性能调优实战」终极关注应用系统性能调优及原理剖析(上册)之后我们接下来进行相关的。流程相关分析优化通过access_log.txt日志分析......
  • MobPush的消息推送原理是什么?
    MobPush智能多通道推送系统作为Mob重磅推出的一款消息推送明星产品,目前已在电商、游戏、新零售、金融等行业广泛应用,它支持多种推送消息类型,全链路数据统计分析助力开发者用......
  • springboot 使用redis和lettuce原理
    springboot使用redis  简介   在SpringBoot中,要访问Redis,可以直接引入spring-boot-starter-data-redis依赖,它实际上是SpringData的一个子项目——SpringDat......
  • nacos注册中心原理
         ......
  • 高防IP的原理是什么
    高防IP是针对互联网服务器遭受大流量的DDoS攻击后导致服务不可用的情况下,推出的付费增值服务,用户在数据不转移的情况下,就可以通过配置高防IP,将攻击流量引流到高防IP,确保源站......
  • PCIe网卡驱动实现分析(二)--- MSI-X中断实现原理
    msix中断实现原理根据中断的上报方式区分,PCIE设备有两种方式向处理器提交中断请求:INTx引脚:和其他外设中断请求一样,通过改变中断请求线电平的方式向处理器提交中......
  • monitor原理
    Java对象头以32位虚拟机为例普通对象数组对象markword(32bits)看后面两位即可区分哪种锁,无所和偏向锁需要看biased_lock的值是1还是0工作原理Monitor被翻译为......
  • 学习计算机组成原理(2)
         ......