博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程透析-CAS
阅读量:2048 次
发布时间:2019-04-28

本文共 1246 字,大约阅读时间需要 4 分钟。

多线程透析-CAS

研究过多线程锁的想必都是知道CAS。

什么是CAS?

CAS (Compare And Swap):比较并交换。是一种轻量级锁的实现方式,也被称为乐观锁。锁的原理就是不会真实的去添加锁,而是通过频繁的去探测访问资源进行比较,直达资源可用进行交换操作。

老规矩还是举例说明:

现在有多个线程a,b,c要对公共资源count进行++操作。

按照之前学习的内容在处理这个程序的时候我们会想到synchronize 和 juc 进行操作,以保障多线程的三大特性(原子性、有序性、可见性–后续详细透析)。

先说说CAS的实现原理,后面再分析synchronize 和juc

CAS实现原理:

在这里插入图片描述
CAS: 全称:Compare And Swap 或者Compare And exchange 比较和交换。
当a,b,c三个线程都对count进行数据++操作时。
在这里插入图片描述
一开始a,b,c都会从内存中拿到数据都是1,这个时时候,a,b,c三者都进行了++操作,都变成了2.
然后都将写入到count里面。
在这里插入图片描述
假如a线程进行操作了,再写入count之前需要做一些操作:比较。就是比较这个count 数据是不是依旧为1(取过来的值),如果依旧是1,那么就把2写入进去。如果正好其他线程已经把count改成3了。
a发现count不在是1了,那么他会把3都读取过来进行++操作,再往回写的时候,再判断count是否为3…一直反复着这样的操作过程就是CAS实现原理。

通过以上透析我们会发现两个问题?

  1. 如果这个count

    被其他线程改成了3,然后又被另一个线程改回了1,那么问题就是现在这个1已经不是a开始读的那个1了,这个就是CAS的一个称为ABA问题
    —> 那这个怎么解决的呢?很简单就是将每次读取的数据加上版本号进行识别。

  2. 还有个问题,就是如果a在计算完往回写入的时候,已经做完了比较,正准备写的过程中count被其他线程改了怎么办?这个问题就是线程原子性问题。

    ----> 这个是怎么解决的呢? 这个就要去研究CAS源码了,在底层中有个lock.cmpxchg是代码。lock是jvm提供的解决原子性问题的,它是一个锁总线,在线程操作为结束的时,不能被其他线程打断。

以上就是CAS的一个实现原理和问题的解决办法。

JDK在1.1~1.2版本的时候用的synchronize,那个时候synchronize只是一个重量级锁 | 悲观锁,之前介绍过,重量级锁是通过OS进行的线程调度接管,所以效率会慢。

于是呢,在JDK1.5之后推出了JUC包,这个包提供了很多原子类都是基于CAS。例如:static AtomicInteger value2 = new AtomicInteger(0);

核心代码:
在这里插入图片描述
可以看到CAS有两个核心的参数(期望值expect、更新值update)
JUC(后面说)。

之后再JDK1.6之后就对synchronize进行了优化,引入了所升级的概念,后面也会详细介绍。

转载地址:http://ojhof.baihongyu.com/

你可能感兴趣的文章
【深度学习】LSTM的架构及公式
查看>>
【深度学习】GRU的结构图及公式
查看>>
【python】re模块常用方法
查看>>
【JavaScript】call()和apply()方法
查看>>
【JavaScript】箭头函数与普通函数的区别
查看>>
前端面试题
查看>>
【JavaScript】常用方法记录
查看>>
C++ 数据存储类型
查看>>
39. Combination Sum
查看>>
剑指Offer 1.二维数组中的查找
查看>>
剑指offer 2.重建二叉树
查看>>
剑指offer 3.二叉树中和为某一值的路径
查看>>
剑指offer 4.替换空格
查看>>
剑指offer 5.从尾到头打印链表
查看>>
剑指offer 6.用两个栈实现队列
查看>>
剑指offer 7.旋转数组的最小数字
查看>>
剑指offer 8-11.斐波那契数列 跳台阶 变态跳台阶 矩形覆盖
查看>>
剑指offer 12.二进制中1的个数
查看>>
剑指offer 13.数值的整数次方
查看>>
剑指offer 14.调整数组顺序使奇数位于偶数前面
查看>>