Java中CAS原理分析(volatile和synchronized浅析)

CAS是什么?


CAS英文解释是比较和交换,是cpu底层的源语,是解决共享变量原子性实现方案,它定义了三个变量,内存地址值对应V,期待值E和要修改的值U,以下图所示,这些变量都是在高速缓存中的,若是两个线程A,B分别经过cas方式同时修改共享变量,假设当A线程先获取时间片,若是发现V的值和E相等就将主内存值更新为U,若是不相等说明线程B在线程A更新以前已经成功更新过,线程A会失败重试,此时根据缓存一致性协议,线程A的本地副本会失效,须要从主内存再同步最新的变量到本地内存副本,在Java中经过调用UnSafe的compareAndSet相似方式调用,底层是c,反编译后操做系统指令是cmpxchg指令。面试

image.png


保证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.自旋时间过长。ide

若是一个线程拿到锁后,一直不释放,其余线程就只能一直循环等待。性能

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

像Automic包下面的基本上都只能保证一个变量的原子性。操作系统


JUC包下面使用!


可能有些童鞋看JDK源码会比较纠结一个点,发现volatile关键字通常都会和cas连用,若是不要volatile会怎么样呢?cas自己只做用于方法,cas对共享变量没有约束,若是不对共享变量作volatile修饰,是不可见的,不可以保证共享变量的实效性,须要等待共享变量主动同步到主内存,这是须要花时间的,效率更低下,全部在JUC并发包里一直能够看到这样的volatile关键字通常都会和cas组合线程


总结


这篇文章,咱们先引出了cas概念,而且说明了它的优缺点,作了案例介绍,简单的和synchronized关键字作了比较,最后,深刻的说明了volatile关键字cas连用的效率,这是我在深刻思考后获得的结论,分享给你们,文章有必定阅读门槛,若是有想搞清楚童鞋,能够1v1私聊讨论交流。但愿你们喜欢。点赞哦!

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

相关文章
相关标签/搜索