java复习之CAS

CAS原理

什么是CAS

CAS是一条CPU并发原语,用于判断内存中某个位置的值是否为预期值,如果是则更改为新的值,如果不是就重新获取这个值再判断修改,这个过程是原子的。
CAS机制中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。

CAS原理

CAS并发原语体现在Java中就是sun.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现CAS汇编指令。这是一套完全依赖于硬件的功能,通过它实现了原子操作。由于CAS是一种系统原语,原语属于操作系统用语,原语由若干指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被终端,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致的问题

CAS的操作过程

  1. 在内存地址V当中,存储着值为10的变量。
  2. 此时线程1想要把变量的的值加一 ,对线程1来说 旧的预期值 A= 10 要修改的新值 B 为 11
  3. 在线程1 修改A之前 线程2 吧变量修改成11
  4. 线程1 执行操作之前首先把 旧的预期值A = 10和 内存中的值进行比较发现 A 和内存中存的值不一样,提交失败
  5. 线程1 重新获取内存中的值 并计算要修改的值 此时对线程1 来说旧的值 A 就为 11 要修改的新值 B 为 12 这个重复尝试的操作为自旋
  6. 这次没有其他线程改变地址V的值。线程1进行比较,发现A和地址V的实际值是相等的
  7. 线程1进行交换,把地址V的值替换为B,也就是12.

synchronized属于悲观锁,悲观的认为程序中的并发情况严重,所以严防死守,
CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去重试更新。

CAS的缺点:

1 CPU开销大 : 在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。
2 不能保证代码块的原子性: CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。
3 可能会产生ABA问题:

什么是ABA问题:

假设内存中有一个值为A的变量,存储在地址V中。我们想有三个线程尝试使用CAS来修改这个值

  1. 线程1 将A 变成了B
  2. 线程2 阻塞了
  3. 线程3 又把B变成A
  4. 线程2 恢复了发现内存中的值还是A 就把这个值变成B

怎么解决ABA问题呢 加个版本号

在Java中,AtomicStampedReference 类就实现了用版本号作比较额CAS机制。这个类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查标志stamped是否为预期标志,如果全部一致,则继续。

操作过程

  1. 假设地址V中存储着变量值A,当前版本号是01。线程1获取了当前值A和版本号01,想要更新为B,但是被阻塞了。
  2. 这时候,内存地址V中变量发生了多次改变,版本号提升为03,但是变量值仍然是A。
  3. 随后线程1恢复运行,进行compare操作。经过比较,线程1所获得的值和地址的实际值都是A,但是版本号不相等,所以这一次更新失败。

java语言CAS底层如何实现?

利用unsafe提供的原子性操作方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值