首页
学习
活动
专区
工具
TVP
发布

CAS与自旋锁

CAS简介

CAS(compare and swap)比较交换,原子操作的一种,用于多线程环境下保持数据一致性。CAS有三个操作数,内存值V,旧的预期值A,要修改的新值B,该操作将

V与A进行比较,如果一样,就将B赋值给V,如果不一样就操作失败。

使用场景

常用替换锁实现对数据的修改操作,如果成功返回,可以选择重试或者其他方法,java中的AtomicInteger类用到了CAS

// AtomicInter method of getAndSet

public final int getAndSet(int newValue) {

return unsafe.getAndSetInt(this, valueOffset, newValue);

}

// Unsafe method of getAndSetInt

public final int getAndSetInt(Object o, long offset, int newValue) {

int v;

do {

v = getIntVolatile(o, offset);

} while (!compareAndSwapInt(o, offset, v, newValue));

return v;

}

存在的问题

ABA问题

进程P1读取了一个数值A,P1被挂起,进程P2开始执行,P2将B修改为A,对于P1来说已经修改过了,继续使用可能会出现问题。需要对其添加版本信息。

自旋锁提出的背景

在多处理系统下,有些资源需要互斥访问,这就引入了锁机制,只有获得了锁,然后才能对资源进行访问,同一时间只能

有一个线程能得到锁,进入临界区。对于其他线程,可以是不断的循环等待,观察锁是否释放,它不用把线程阻塞,这就是自旋锁。

另外一种就是没有获得锁就阻塞自己,请求CPU调度别的线程,互斥锁

自旋锁的原理

和互斥锁类似,自旋锁是一种比较低级的保护数据结构或者代码片段的原始方式,会出现递归死锁和占用很多的CPU资源

递归死锁

试图递归地获得自旋锁必然会引起死锁:递归程序的持有实例在第二个实例循环,以试图获得相同自旋锁时,不会释放此自旋锁。在递归程序中使用自旋锁应遵守下列策略

:递归程序决不能在持有自旋锁时调用它自己,也决不能在递归调用时试图获得相同的自旋锁。

此外如果一个进程已经将资源锁定,那么,即使其它申请这个资源的进程不停地疯狂“自旋”,也无法获得资源,从而进入死循环。

占用很多的CPU资源

由于线程一直在循环等待,必定会造成CPU使用很高,通常情况下,会有一个尝试的限制,如果循环超过了限制,就挂起

使用场景

自旋锁比较锁使用者保持锁时间很短的情况,jdk1.7中的concurrentHashMap中put方法使用了自旋锁。

参考链接

https://zh.wikipedia.org/wiki/%E6%AF%94%E8%BE%83%E5%B9%B6%E4%BA%A4%E6%8D%A2

https://liuzhengyang.github.io/2017/05/11/cas/

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180618G1FRGD00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券