纠纷奇闻作文社交美文家庭
聚热点
家庭城市
爱好生活
创业男女
能力餐饮
美文职业
心理周易
母婴奇趣
两性技能
社交传统
新闻范文
工作个人
思考社会
作文职场
家居中考
兴趣安全
解密魅力
奇闻笑话
写作笔记
阅读企业
饮食时事
纠纷案例
初中历史
说说童话
乐趣治疗

一篇搞定CAS,深度讲解,面试实践必备

8月24日 火云谷投稿
  背景
  在高并发的业务场景下,线程安全问题是必须考虑的,在JDK5之前,可以通过synchronized或Lock来保证同步,从而达到线程安全的目的。但synchronized或Lock方案属于互斥锁的方案,比较重量级,加锁、释放锁都会引起性能损耗问题。
  而在某些场景下,我们是可以通过JUC提供的CAS机制实现无锁的解决方案,或者说是它基于类似于乐观锁的方案,来达到非阻塞同步的方式保证线程安全。
  CAS机制不仅是面试中会高频出现的面试题,而且也是高并发实践中必须掌握的知识点。如果你目前对CAS还不甚了解,或许只有模糊的印象,这篇文章一定值得你花时间学习一下。什么是CAS?
  CAS是CompareAndSwap的缩写,直译就是比较并交换。CAS是现代CPU广泛支持的一种对内存中的共享数据进行操作的一种特殊指令,这个指令会对内存中的共享数据做原子的读写操作。其作用是让CPU比较内存中某个值是否和预期的值相同,如果相同则将这个值更新为新值,不相同则不做更新。
  本质上来讲CAS是一种无锁的解决方案,也是一种基于乐观锁的操作,可以保证在多线程并发中保障共享资源的原子性操作,相对于synchronized或Lock来说,是一种轻量级的实现方案。
  Java中大量使用了CAS机制来实现多线程下数据更新的原子化操作,比如AtomicInteger、CurrentHashMap当中都有CAS的应用。但Java中并没有直接实现CAS,CAS相关的实现是借助CC调用CPU指令来实现的,效率很高,但Java代码需通过JNI才能调用。比如,Unsafe类提供的CAS方法(如compareAndSwapXXX)底层实现即为CPU指令cmpxchg。CAS的基本流程
  下面我们用一张图来了解一下CAS操作的基本流程。
  在上图中涉及到三个值的比较和操作:修改之前获取的(待修改)值A,业务逻辑计算的新值B,以及待修改值对应的内存位置的C。
  整个处理流程中,假设内存中存在一个变量i,它在内存中对应的值是A(第一次读取),此时经过业务处理之后,要把它更新成B,那么在更新之前会再读取一下i现在的值C,如果在业务处理的过程中i的值并没有发生变化,也就是A和C相同,才会把i更新(交换)为新值B。如果A和C不相同,那说明在业务计算时,i的值发生了变化,则不更新(交换)成B。最后,CPU会将旧的数值返回。而上述的一系列操作由CPU指令来保证是原子的。
  在《Java并发编程实践》中对CAS进行了更加通俗的描述:我认为原有的值应该是什么,如果是,则将原有的值更新为新值,否则不做修改,并告诉我原来的值是多少。
  在上述路程中,我们可以很清晰的看到乐观锁的思路,而且这期间并没有使用到锁。因此,相对于synchronized等悲观锁的实现,效率要高非常多。基于CAS的AtomicInteger使用
  关于CAS的实现,最经典最常用的当属AtomicInteger了,我们马上就来看一下AtomicInteger是如何利用CAS实现原子性操作的。为了形成更新鲜明的对比,先来看一下如果不使用CAS机制,想实现线程安全我们通常如何处理。
  在没有使用CAS机制时,为了保证线程安全,基于synchronized的实现如下:publicclassThreadSafeTest{publicstaticvolatileinti0;publicsynchronizedvoidincrease(){i;}}
  至于上面的实例具体实现,这里不再展开,很多相关的文章专门进行讲解,我们只需要知道为了保证i的原子操作,在increase方法上使用了重量级的锁synchronized,这会导致该方法的性能低下,所有调用该方法的操作都需要同步等待处理。
  那么,如果采用基于CAS实现的AtomicInteger类,上述方法的实现便变得简单且轻量级了:publicclassThreadSafeTest{privatefinalAtomicIntegercounternewAtomicInteger(0);publicintincrease(){returncounter。addAndGet(1);}}
  之所以可以如此安全、便捷的来实现安全操作,便是由于AtomicInteger类采用了CAS机制。下面,我们就来了解一下AtomicInteger的功能及源码实现。CAS的AtomicInteger类
  AtomicInteger是java。util。concurrent。atomic包下的一个原子类,该包下还有AtomicBoolean,AtomicLong,AtomicLongArray,AtomicReference等原子类,主要用于在高并发环境下,保证线程安全。AtomicInteger常用API
  AtomicInteger类提供了如下常见的API功能:publicfinalintget():获取当前的值publicfinalintgetAndSet(intnewValue):获取当前的值,并设置新的值publicfinalintgetAndIncrement():获取当前的值,并自增publicfinalintgetAndDecrement():获取当前的值,并自减publicfinalintgetAndAdd(intdelta):获取当前的值,并加上预期的值voidlazySet(intnewValue):最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
  上述方法中,getAndXXX格式的方法都实现了原子操作。具体的使用方法参考上面的addAndGet案例即可。AtomicInteger核心源码
  下面看一下AtomicInteger代码中的核心实现代码:publicclassAtomicIntegerextendsNumberimplementsjava。io。Serializable{privatestaticfinalUnsafeunsafeUnsafe。getUnsafe();privatestaticfinallongvalueOstatic{try{用于获取value字段相对当前对象的起始地址的偏移量valueOffsetunsafe。objectFieldOffset(AtomicInteger。class。getDeclaredField(value));}catch(Exceptionex){thrownewError(ex);}}返回当前值publicfinalintget(){}递增加detlapublicfinalintgetAndAdd(intdelta){1、this:当前的实例2、valueOffset:value实例变量的偏移量3、delta:当前value要加上的数(valuedelta)。returnunsafe。getAndAddInt(this,valueOffset,delta);}递增加1publicfinalintincrementAndGet(){returnunsafe。getAndAddInt(this,valueOffset,1)1;}。。。}
  上述代码以AtomicIntegerincrementAndGet方法为例展示了AtomicInteger的基本实现。其中,在static静态代码块中,基于Unsafe类获取value字段相对当前对象的起始地址的偏移量,用于后续Unsafe类的处理。
  在处理自增的原子操作时,使用的是Unsafe类中的getAndAddInt方法,CAS的实现便是由Unsafe类的该方法提供,从而保证自增操作的原子性。
  同时,在AtomicInteger类中,可以看到value值通过volatile进行修饰,保证了该属性值的线程可见性。在多并发的情况下,一个线程的修改,可以保证到其他线程立马看到修改后的值。
  通过源码可以看出,AtomicInteger底层是通过volatile变量和CAS两者相结合来保证更新数据的原子性。其中关于Unsafe类对CAS的实现,我们下面详细介绍。CAS的工作原理
  CAS的实现原理简单来说就是由Unsafe类和其中的自旋锁来完成的,下面针对源代码来看一下这两块的内容。UnSafe类
  在AtomicInteger核心源码中,已经看到CAS的实现是通过Unsafe类来完成的,先来了解一下Unsafe类的作用。这里我们简单概述一下。
  sun。misc。Unsafe是JDK内部用的工具类。它通过暴露一些Java意义上说不安全的功能给Java层代码,来让JDK能够更多的使用Java代码来实现一些原本是平台相关的、需要使用native语言(例如C或C)才可以实现的功能。该类不应该在JDK核心类库之外使用,这也是命名为Unsafe(不安全)的原因。
  JVM的实现可以自由选择如何实现Java对象的布局,也就是在内存里Java对象的各个部分放在哪里,包括对象的实例字段和一些元数据之类。
  Unsafe里关于对象字段访问的方法把对象布局抽象出来,它提供了objectFieldOffset()方法用于获取某个字段相对Java对象的起始地址的偏移量,也提供了getInt、getLong、getObject之类的方法可以使用前面获取的偏移量来访问某个Java对象的某个字段。在AtomicInteger的static代码块中便使用了objectFieldOffset()方法。
  Unsafe类的功能主要分为内存操作、CAS、Class相关、对象操作、数组相关、内存屏障、系统相关、线程调度等功能。这里我们只需要知道其功能即可,方便理解CAS的实现,注意不建议在日常开发中使用。Unsafe与CAS
  AtomicInteger调用了UnsafegetAndAddInt方法:publicfinalintincrementAndGet(){returnunsafe。getAndAddInt(this,valueOffset,1)1;}
  上述代码等于是AtomicInteger调用UnSafe类的CAS方法,JVM帮我们实现出汇编指令,从而实现原子操作。
  在Unsafe中getAndAddInt方法实现如下:publicfinalintgetAndAddInt(Objectvar1,longvar2,intvar4){intvar5;do{var5this。getIntVolatile(var1,var2);}while(!this。compareAndSwapInt(var1,var2,var5,var5var4));returnvar5;}
  getAndAddInt方法有三个参数:第一个参数表示当前对象,也就是new的那个AtomicInteger对象;第二个表示内存地址;第三个表示自增步伐,在AtomicIntegerincrementAndGet中默认的自增步伐是1。
  getAndAddInt方法中,首先把当前对象主内存中的值赋给val5,然后进入while循环。判断当前对象此刻主内存中的值是否等于val5,如果是,就自增(交换值),否则继续循环,重新获取val5的值。
  在上述逻辑中核心方法是compareAndSwapInt方法,它是一个native方法,这个方法汇编之后是CPU原语指令,原语指令是连续执行不会被打断的,所以可以保证原子性。
  在getAndAddInt方法中还涉及到一个实现自旋锁。所谓的自旋,其实就是上面getAndAddInt方法中的dowhile循环操作。当预期值和主内存中的值不等时,就重新获取主内存中的值,这就是自旋。
  这里我们可以看到CAS实现的一个缺点:内部使用自旋的方式进行CAS更新(while循环进行CAS更新,如果更新失败,则循环再次重试)。如果长时间都不成功的话,就会造成CPU极大的开销。
  另外,Unsafe类还支持了其他的CAS方法,比如compareAndSwapObject、compareAndSwapInt、compareAndSwapLong。CAS的缺点
  CAS高效的实现了原子性操作,但在以下三方面还存在着一些缺点:循环时间长,开销大;只能保证一个共享变量的原子操作;ABA问题;
  下面就这个三个问题详细讨论一下。循环时间长开销大
  在分析Unsafe源代码的时候我们已经提到,在Unsafe的实现中使用了自旋锁的机制。在该环节如果CAS操作失败,就需要循环进行CAS操作(dowhile循环同时将期望值更新为最新的),如果长时间都不成功的话,那么会造成CPU极大的开销。如果JVM能支持处理器提供的pause指令那么效率会有一定的提升。只能保证一个共享变量的原子操作
  在最初的实例中,可以看出是针对一个共享变量使用了CAS机制,可以保证原子性操作。但如果存在多个共享变量,或一整个代码块的逻辑需要保证线程安全,CAS就无法保证原子性操作了,此时就需要考虑采用加锁方式(悲观锁)保证原子性,或者有一个取巧的办法,把多个共享变量合并成一个共享变量进行CAS操作。ABA问题
  虽然使用CAS可以实现非阻塞式的原子性操作,但是会产生ABA问题,ABA问题出现的基本流程:进程P1在共享变量中读到值为A;P1被抢占了,进程P2执行;P2把共享变量里的值从A改成了B,再改回到A,此时被P1抢占;P1回来看到共享变量里的值没有被改变,于是继续执行;
  虽然P1以为变量值没有改变,继续执行了,但是这个会引发一些潜在的问题。ABA问题最容易发生在lockfree的算法中的,CAS首当其冲,因为CAS判断的是指针的地址。如果这个地址被重用了呢,问题就很大了(地址被重用是很经常发生的,一个内存分配后释放了,再分配,很有可能还是原来的地址)。
  维基百科上给了一个形象的例子:你拿着一个装满钱的手提箱在飞机场,此时过来了一个火辣性感的美女,然后她很暖昧地挑逗着你,并趁你不注意,把用一个一模一样的手提箱和你那装满钱的箱子调了个包,然后就离开了,你看到你的手提箱还在那,于是就提着手提箱去赶飞机去了。
  ABA问题的解决思路就是使用版本号:在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么ABA就会变成1A2B3A。
  另外,从Java1。5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。小结
  本文从CAS的基本使用场景、基本流程、实现类AtomicInteger源码解析、CAS的Unsafe实现解析、CAS的缺点及解决方案等方面来全面了解了CAS。
投诉 评论 转载

淦这个是什么梗淦和干读音一样被up主交流应用淦(读音n)因为读音和干一样,这就是淦这个梗的来源了。不过,淦这个词在生活中基本上是用不到的,它原本的意思是水渗入船中,一般在古书中会出现。不过这两年,淦……11月1日区块链资讯汇总(五)【20:03】【NEAR基金会在韩国推出Web3区域中心】11月1日消息,瑞士非营利组织NEAR基金会今天宣布已在韩国启动了一个Web3区域中心,致力于Web3创新、业务发展、……西溪湿地并蒂莲开花一天就被折并蒂莲的名字的来源及花语是什么近日,杭州西溪湿地公园中的一支并蒂莲开花仅一天就被折断了,不少网友在感到惋惜的时候,也纷纷吐槽观赏的人没有素质!并蒂莲的名字的来源是什么呢?并蒂莲的花语是什么?一起来看一下。1……一篇搞定CAS,深度讲解,面试实践必备背景在高并发的业务场景下,线程安全问题是必须考虑的,在JDK5之前,可以通过synchronized或Lock来保证同步,从而达到线程安全的目的。但synchronize……女生在家被偷拍三年自己浴室被暗藏摄像头的可怕真相女生在家被偷拍三年的消息引关注,看到这是不是感觉太可怕了呢?女孩在家被偷拍,竟长达三年!是哪个变态如此丧心病狂!据悉,广西贺州的女生卷卷(化名)微博爆料称,发现自己初三时在家洗……五一出游正当时,记得带上5款零食,营养又美味,一家老小皆爱吃五一出游正当时,记得带上5款零食,营养又美味,一家老小皆爱吃五一小长假是上班族和学生党一年中最期待的假期。正值春末夏初,户外微风拂面,阳光正好,正是出去游玩的好时节。就算……法学专家为北京冬奥会保驾护航北京冬奥会日益临近。视觉中国供图北京2022年冬奥会和冬残奥会即将启幕。围绕赛会可能面临的法律风险、防范重点,中国法学会体育法学研究会日前邀请体育法理论界和实务界的专家代……盘点世界上最长的蜈蚣可以当腰带了太吓人了(图)盘点世界上最长的蜈蚣:可以当腰带了太吓人了(图)盘点世界上最长的蜈蚣,可以当腰带了。蜈蚣有着奇数的腿对,好奇葩对不对,那么你知道世界上最大的蜈蚣吗?长度有多少,一起来看看……被蜈蚣咬了伤口图片被蜈蚣咬了怎么办(图)被蜈蚣咬了伤口图片:被蜈蚣咬了怎么办(图)上面有提到过被毒蜂蛰伤的情况,如果被蜈蚣咬伤该怎么办呢?单单看到蜈蚣的图片就吓得魂飞魄散,最好永远都不要遇到它,下面这篇经验将要……波兹洛娃将成为首位执裁斯诺克大师赛决赛女裁判国际在线消息:2022年斯诺克大师赛决赛将于英国当地时间1月16日举行,在今年的决赛赛场上,除了选手们的精彩表现值得期待外,决赛裁判也成为了热议的焦点。29岁的保加利亚女裁判波……世界上最大的蜈蚣巨人蜈蚣长0。62米(图)世界上最大的蜈蚣:相信很多见到蜈蚣的第一反应就是非常害怕,的确蜈蚣的多足加上其有剧毒让一般人看到都想远离而知,那你可知道世界上最大的蜈蚣有多大?有未确切的报道,人类曾经捕捉的最……大爆冷!张本智和状态低迷23输球遭遇3连败,难掩泪水痛哭流涕北京时间2月19日,日本T联赛正在进行。正在进行的是日本东京俱乐部迎战彩玉俱乐部。首盘比赛,日本东京俱乐部男双组合大岛祐哉松岛辉空迎战彩玉俱乐部选手上田仁松平健太。最终,后者上……
iPhone15Pro或将配备潜望镜镜头小虎转中路是真的!Doinb爆料RNG中单已离队,想抢果子哥脾胃虚,脸色暗黄,把手这样按按,按出漂亮的你东部排名更新挥拳锁喉,大规模群殴!欧文不再回更衣室了一个人越来越有福气,是有迹象的坦克世界第四期大领土战报(2。17)卡无限火力方法刚出一天,官方就紧急修复,快乐没了23个国际品牌首次入驻,奢侈品的海南机会春节后控制油腻食物,健康饮食如何吃女篮世界杯中国已经提前晋级,后两场全输也没关系图片报多特准备提供1年续约合同,但罗伊斯须接受降薪600万欧国米首败暴露3差,中场先天缺陷何人可解,边路后天不足谁人可依
阴魂造句用阴魂造句大全产后卫生健康方法要适当,不妨看看吧!双眼造句用双眼造句大全北京英国工作签证办理指南牙龈为何会出血呢李姓二个字女孩大全海洋污染物有几个种类环境压力会限制女性做出战略决策的能力高速过错过叉道倒车2米会被处罚吗北京一小酒厂20年前破产倒闭,如今一瓶价格比茅台贵,背景深厚健脾和胃要穴绝地求生最危险的4种搭配图1集体送死图4智商下线!

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找美丽时装彩妆资讯历史明星乐活安卓数码常识驾车健康苹果问答网络发型电视车载室内电影游戏科学音乐整形