每天一个小细节:什么是CAS

什么是CAS

CAS是compare and swap的缩写,译为比较与交换,都说它厉害,那么它究竟厉害在哪呢?它可以做到原子性的修改内存中的数据,这是什么概念?我们的锁不就是为了处理数据修改带来的线程安全问题吗?这么厉害的玩意使用是个什么样的流程,让我们来研究一下:
在这里插入图片描述
这样为什么是原子性的呢,因为每次数据修改前都会先比较我们拷贝的A‘和A的值是否相等,如果期间有其他线程已经修改过A的值,那么就会重新获取A’的值,再继续判断,就不会出现两个线程操作同一数据,出现都操作的旧数据的问题了。

伪代码:(cas是硬件指令,伪代码只是帮助理解)

boolean cas(A,A',B){
	if(A==A'){
		A=B;//修改内存A的值为B
		return true;
	}
	return false;
}

CAS的用处

1.原子类

通过借助cas的力量,java标准库提供了java.util.concurrent.atomic包,里面包含如下类:

在这里插入图片描述
这些类如何使用在这里不展开说,我们只说一个最典型的:在这里插入图片描述
这个类的常用方法有:
incrementAndGet() 前置++
getAndIncrement() 后置++
getAndDecrement() 后置–
decrementAndGet() 前置–
这个类内部有一个成员变量count,通过这些方法可以原子性的修改count的值,多半适用于计数器。

2.实现自旋锁

我们都知道自旋锁是没抢到锁,不挂起等待而持续的去尝试获取锁,那么这个持续的尝试获取锁也是借助了cas的力量,通过cas持续的观察当前锁是被哪个线程占有,只要发现当前锁没有线程占用,里面尝试获取。伪代码如下:

Thread getLock=null;//该变量代表哪个线程获取当前锁
void lock(){
	public void lock(){
// 通过 CAS 看当前锁是否被某个线程持有.(getLock是否为null)
// 如果这个锁已经被别的线程持有, 那么就自旋等待.(getLock!=null)
// 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程.(getlock==null)
		while(!CAS(this.getLock, null, Thread.currentThread())){}
	}
}

CAS的缺点(ABA问题)

说了cas那么多优点,它一点缺点都没有是不是有点不太礼貌了。正所谓人无完人,cas也是这样,那么这里就介绍一下cas的缺点也就是ABA问题。

什么是ABA问题:
在这里插入图片描述
因为我们cas的修改前提是判断A‘和A是否相同,这就有可能出现其实A已经被修改过,只是值没变,但A已经不是哪个A了,就像我们的滑稽老哥已经不只是谈过一次女票了。虽然大部分情况下ABA问题并没有什么影响,但再一些特殊情况还是有影响的,所以这个问题必须要解决。
解决方案:引入版本号(或者修改时间)
通过比较我们的版本号,来判断当前内存值有没有被修改过。具体流程:内存A不仅存我们的数据同时存储一个版本号V,每次修改成功时,版本号V+1,每次修改前再拷贝一份版本号并+1称作V’,即将修改的时候,比较V‘是否大于V,是就修改,不是就重新获取V’,这样就可能有效的解决ABA问题

相关面试题:

  1. 讲解下你自己理解的 CAS 机制
  2. ABA问题怎么解决?

结束语

又是一个小细节

这里是引用

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值