当前位置:   article > 正文

CAS简介

cas

目录

一.为什么要有CAS

二.什么是CAS机制

三. CAS工作原理

四.CAS的缺点

五.关于CAS中的ABA问题

解决方案


一.为什么要有CAS

我们在多线程安全中有一个经典的双线程++问题

  1. public static int count = 0;
  2. public static void main(String[] args) throws InterruptedException {
  3. Thread t1 = new Thread(()->{
  4. for (int i = 0; i < 10000; i++) {
  5. count++;
  6. }
  7. });
  8. Thread t2 = new Thread(()->{
  9. for (int i = 0; i < 10000; i++) {
  10. count++;
  11. }
  12. });
  13. t1.join();
  14. t2.join();
  15. t1.start();
  16. t2.start();
  17. Thread.sleep(1000);
  18. System.out.println(count);
  19. }

就是两个线程同时进行++这个操作,就会导致结果出错

这里结果应该=20000

 我们由此知道了++操作,分为三步,应该加锁确保他的操作是原子性

  1. //可以将++操作打包到一个枷锁的方法里面
  2. synchronized public void func(){
  3. count++;
  4. }

但是这样枷锁和解锁,实际上效率并不高效,由此我们引入了一个新的概念

CAS机制

二.什么是CAS机制

简单来说就是进行原子性操作

比如,我们可以将上面的加锁和解锁替换成CAS中的原子操作

所谓CAS的原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。如AtomicBoolean,AtomicUInteger,AtomicLong。

让我们用一用

  1. import java.util.concurrent.atomic.AtomicInteger;
  2. public class demo3 {
  3. //将int count变为AtomicInteger count = new AtomicInteger()
  4. public static AtomicInteger count = new AtomicInteger();
  5. public static void main(String[] args) throws InterruptedException {
  6. Thread t1 = new Thread(()->{
  7. for (int i = 0; i < 10000; i++) {
  8. //使用原子性的++操作
  9. count.incrementAndGet();
  10. }
  11. });
  12. Thread t2 = new Thread(()->{
  13. for (int i = 0; i < 10000; i++) {
  14. //使用原子性的++操作
  15. count.incrementAndGet();
  16. }
  17. });
  18. t1.join();
  19. t2.join();
  20. t1.start();
  21. t2.start();
  22. Thread.sleep(1000);
  23. System.out.println(count);
  24. }
  25. }

结果就好了

三. CAS工作原理

我们拿++这个操作来举例

假如我现在有两个线程

线程1和线程2

此时线程1中,有一个数字10开始进行++操作

如果线程2此刻没有进行++操作,也就是说目前只有线程1在进行这个操作的话

就是如下情况

 但是如果,此时线程2也有个++操作,并且比线程1先执行完毕的话

 

 所以这样永远能保证++操作的原子性

四.CAS的缺点

1) CPU开销过大

在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。

2) 不能保证代码块的原子性

CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

3) ABA问题(重点问题)

这是CAS机制最大的问题所在。

五.关于CAS中的ABA问题

经典ABA例子:取钱问题

假如现在有一位老哥在CAS的取款机上取钱

 这个时候,这个CAS的取款机,在一瞬间开创了线程A和线程B

相当于两个线程在同时进行-操作

如果是这样的话,按照CAS的机制,那么我们理想情况下,应该是这样

但是如果遇到了一种意外情况

线程B遇到了BUG,停止了运行

恰好这个时候,滑稽老哥的妈妈给他汇过去50元

 然后这个时候,BUG修复了,线程B开始运行

 于是我们的滑稽老铁就白白损失了50元

这就是ABA问题

其实B修好了bug之后,不应该以原来的100作为基准

而是应该以线程C没有修改之前的线程A运行的结果作为基准

这里的B是拿C运行的结果作为基准来和原来进行比较,这样肯定是错误的

解决方案

加上版本号

将线程A和B设置为同一版本号,经过比较

如果版本号不同的话,那么我们直接让这个操作失效就好了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/293838
推荐阅读
相关标签
  

闽ICP备14008679号