CAS是什么?


CAS英文解释是比拟和替换,是cpu底层的源语,是解决共享变量原子性实现计划,它定义了三个变量,内存地址值对应V,期待值E和要批改的值U,如下图所示,这些变量都是在高速缓存中的,如果两个线程A,B别离通过cas形式同时批改共享变量,假如当A线程先获取工夫片,如果发现V的值和E相等就将主内存值更新为U,如果不相等阐明线程B在线程A更新之前曾经胜利更新过,线程A会失败重试,此时依据缓存一致性协定,线程A的本地正本会生效,须要从主内存再同步最新的变量到本地内存正本,在Java中通过调用UnSafe的compareAndSet相似形式调用,底层是c,反编译后操作系统指令是cmpxchg指令。

保障i++原子性


你肯定会有一个疑难,被volatile润饰的变量i,i++为什么会有线程平安问题呢,也就是原子性的问题,咱们还是举一个经典的i++案例一步步剖析吧!咱们晓得在多线程状况下volatile保障了共享变量的可见性,程序行,但唯独不能保障原子性,起因是i++是一个复合操作,大抵能够分成3步,1.先从主内存拿到最新的i值,2.将i加1这个操作保留到操作数栈,3.从栈中取出i加1的值写回到主内存。OK,当线程AB同时执行i++操作时,比方线程A先获取工夫片,执行完第2步,这是线程A还未执行完,工夫片调配给线程B,B顺利执行完所有操作后并同步了主内存,假如咱们i的初始值是1,那么此时主内存值是2,因为线程B执行结束,cpu工夫片又回到线程A手上,做第3步操作,此时同步到主内存的值还是2,看,线程A,B各做了一次加1的操作,但最终后果可能是2,cas的作用就来了,他能保障i++操作的原子性,为什么能保障原子性呢?cas能够把下面三个操作合并成一个操作,是原子的。

有什么益处?


大家都晓得解决多线程平安须要用到锁的,能够用synchronized来解决,然而synchronized也有它的劣势,最次要是它是阻塞的,阻塞会有什么问题?性能啊,这是计算机人不能忍的,频繁内核外核切换,会重大节约系统资源,所以就提了cas这个乐观锁概念,它是非阻塞的,操作系统不必在内核态与用户态来回切换,相当于用while循环形式获取锁,在性能上有肯定晋升。即便这样,也会有肯定问题,上面咱们来看看。

有什么问题?


1.ABA问题。

这个案例比较简单,线程A把共享变量i,从1变成2,再变成1,线程B想把i变成2,原本应该是不会胜利,因为即时变量i当初是1,然而它的状态变动了,他的解决方案是版本号。相当于批改胜利一次版本号减少1,就能够解决了,已经被面试官问到一个问题,cas是线程平安的吗?答案不是线程平安的。

2.自旋工夫过长。

如果一个线程拿到锁后,始终不开释,其余线程就只能始终循环期待。

3.只能保障一个共享变量的原子性。

像Automic包上面的基本上都只能保障一个变量的原子性。

JUC包上面应用!


可能有些童鞋看JDK源码会比拟纠结一个点,发现volatile关键字个别都会和cas连用,如果不要volatile会怎么样呢?cas自身只作用于办法,cas对共享变量没有束缚,如果不对共享变量做volatile润饰,是不可见的,不可能保障共享变量的实效性,须要期待共享变量被动同步到主内存,这是须要花工夫的,效率更低下,所有在JUC并发包里始终能够看到这样的volatile关键字个别都会和cas组合。

总结


这篇文章,咱们先引出了cas概念,并且阐明了它的优缺点,做了案例介绍,简略的和synchronized关键字做了比拟,最初,深刻的阐明了volatile关键字cas连用的效率,这是我在深刻思考后失去的论断,分享给大家,文章有肯定浏览门槛,如果有想搞清楚童鞋,能够1v1私聊探讨交换。心愿大家喜爱。点赞哦!

我是叫练,边叫边练,欢送点赞和评论。