并发编程 — CAS 原理详解

在JDK1.5引入的 J.U.C包中的原子类以及Lock等都是基于 volatile 关键结合 CAS 操作实现的,为了能够搞明白 原子类以及 Lock锁的原理首先要了解 volatile 原理以及 CAS原理,上篇文章我们说了volatile关键字,这篇咱们就聊聊 什么是 CAS 操作。

悲观锁与乐观锁

在说CAS操作之前咱们先说一下什么是悲观锁和乐观锁。

悲观锁

悲观锁就是总是加锁最坏的情况,所以每次去拿数据时都认为别人会修改,所以每次操作共享数据时都会上锁,这样当别人需要访问共享数据时,就必须阻塞等待,直到它拿到锁。传统的关系型数据库里面就用到了很多这种锁机制,比如行锁、表锁等,都是在操作之前先加上锁。在Java中 synchronized 和 ReentrantLock 等都是独占的,也就是悲观锁。

悲观锁可以理解为就是 “总有刁民想害朕”。

乐观锁

乐观锁就是总是情况最好的,每次去拿共享数据的时候认为别人不会修改,所以不会上锁,但是在更新数据的时候会判断一下在此期间别人是否更改了数据。一般可以通过版本号和 CAS算法实现。乐观锁适用于读多写少的场景,这样可以提供吞吐量

什么是CAS

CAS 即 Compare And Swap (比较与交换),是一种有名的无锁算法。CAS算法主要涉及到三个参数:

  • 主内存中存放的的值V,也就是线程共享的值。
  • 线程上次从内存中读取的V值 A,线程私有的,存放在线程栈帧中,或者CPU缓存中的值。
  • 需要写入主内存改些V的值B,线程对A计算后的值。

大致流程如下所示:

说明:Java中实现CAS操作 实质上调用的是 本地方法完成的,也就是以来的是 CPU 执行的汇编指令cmpxchgl。对汇编指令感兴趣的,可以参阅Intel的CPU指令手册,其中就有对该指令的详细说明,具体地址为:http://heather.cs.ucdavis.edu/~matloff/50/PLN/lock.pdf

CAS带来的三大问题

ABA问题

因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么CAS进行检查的时候发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面加上版本号,每次变量更新的时候把版本号加1,那么A->B->A就会变成1A->2B->3A。从Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前的标志是否等于预期标志,如果全部相等,则以原子方式将该应用和该标志的值设置为给定的更新值。

开销大的问题

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销,如果JVM能支持处理器提供的pause指令,那么效率会有一定的提升。pause指令有两个作用:

第一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间取决于具体实现的版本,在一些处理器上延迟时间是零;

第二,它可以避免在循环的时候因内存顺序冲突(Memory Order Violation)而引起CPU流水线被清空,从而提高CPU的实行效率。

只能保证一个共享变量的原子操作

当对一个共享变量执行操作时,我们可以使用循环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ji=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之前的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

总结

本篇文章首先介绍了什么是悲观锁和乐观锁,然后介绍了 CAS 原理,CAS 就是 比较并交换,也就是在写入时先比较 主内存中值是否跟之前读取的旧值相等,如果相等就更新,如果不相等就再次读取计算,循环往复。CAS 在提高性能的同时,也带来了三大问题。明白三大问题能够更好的使用 CAS操作,以及后续的 原子操作类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值