大家都在看
CAS技术实现之底层原理
最佳答案
小伙伴们都知道,i++其实并非是原子性操作,在多线程环境下会有线程安全的问题,下面我们来写个测试demo来验证这条结论。
通过上面的小例子我们可以发现每次计算的结果都有偏差。为什么会存在偏差呢?这是因为JMM将内存分为工作内存+主内存。我们的运算工作是在工作内存中进行,然后再将得到的值同步到主内存中。
通过上图我们可以看到,一开始主内存中i=0,此时线程A把i读到工作内存,并开始进行i++的运算,然后把运算结果i=1同步给主内存。但是因为整个过程并不是原子性的(线程A运算的过程中,线程B也可以进行运算),这时候线程A还没有来得及把计算后的值刷新回主内存,线程B就开始进行了i++的操作,此时线程B拿到的i的值为0,而不是线程A计算后的1,这样线程B经过运算,得到的结果也是1,这样就导致最终结果是1而不是我们期望的2,从而造成线程安全问题。
1.synchronized锁
当我们对i++加了synchronized锁后,就可以保证它具有原子性,从而保证同一时刻只有一个线程能对i进行++操作,进而保证线程安全。
通过synchronized锁后,得到的结果跟预期结果相符。synchronized底层原理不是本篇文章的重点,后面会单出一篇文章来进行剖析。
2.通过J.U.C包下的AtomicInteger
ok,前面铺垫那么多,现在正式引入本文的重点: CAS ,AtomicInteger就是基于CAS技术实现的。
CAS,Compare and Swap即比较并替换。它是乐观锁思想的一种实现方式。
通过图我们可以看出CAS实现原理:CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则什么都不做并返回false。
1.点开getAndIncrement()方法,我们会发现AtomicInteger调用了Unsafe的getAndInt()方法
小知识: JVM是规范,目前市面上主要有四种实现
1)Hotspot:最常用的jvm实现
2)JRocket:JRocket是BEA公司的JVM.使用WebLogic的用户,往往使用JRocket虚拟机.
3)J9:IBM公司的JVM
4)Harmony:IBM和Intel搞的开源JVM. IBM牵头,主力是Intel.
找到 atomic_linux_x86.inline.hpp ,找到cmpxchg方法
CAS是一种乐观锁,采用自旋的方式来等待其他线程完成工作。在竞争比较低且等待时间短的任务场景中表现优异。
1)因为CAS采用自旋方式,而自旋是需要占用CPU资源的。
2)只能保持一个变量的原子操作
3) ABA问题
这里我来给小伙伴解释下什么是ABA问题,还是拿CAS流程图来讲
前面我们也提到了,CAS虽然会占用CPU资源,但是只在用户态就可以完成加锁的过程(不需要涉及到内核态)。那么线程数较少,竞争不激烈,等待时间短的场景就是CAS的最佳适用场景。小伙伴们get到了吗?
声明:知趣百科所有作品均由用户自行上传分享,仅供网友学习交流。若您的权利被侵害,请在页面底部查找“联系我们”的链接,并通过该渠道与我们取得联系以便进一步处理。