CAS解析

CAS

概念

CAS是支持并发的第一个处理器提供原子的测试并设置操作,通常在单位上运行这项操作。操作数为V,A,B。
处理器(包括 Intel 和 Sparc 处理器)使用的最通用的方法是实现名为 比较并转换或 CAS 的原语。(在 Intel 处理器中,比较并交换通过指令的 cmpxchg 系列实现。PowerPC 处理器有一对名为“加载并保留”和“条件存储”的指令,它们实现相同的目地;MIPS 与 PowerPC 处理器相似,除了第一个指令称为“加载链接”。)
CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置的值即可。
通常将 CAS 用于同步的方式是从地址 V 读取值 A,执行多步计算来获得新值 B,然后使用 CAS 将 V 的值从 A 改为 B。如果 V 处的值尚未同时更改,则 CAS 操作成功。
类似于 CAS 的指令允许算法执行读-修改-写操作,而无需害怕其他线程同时修改变量,因为如果其他线程修改变量,那么 CAS 会检测它(并失败),算法可以对该操作重新计算。清单 3 说明了 CAS 操作的行为(而不是性能特征),但是 CAS 的价值是它可以在硬件中实现,并且是极轻量级的(在大多数处理器中)。

基本原理

在这里插入图片描述
采用了乐观锁思想,首先线程获取到共享资源变量的值,然后再计算出要赋予共享变量的新值,最后,调用硬件处理器的CAS机制,保证原子操作:首先比较内存中共享变量现在的值是否与线程中存入的共享变量的旧值相等,如果相等,则将新值赋予共享变量,赋值成功,这个过程是原子性的,由底层处理器完成,在这期间共享变量值不会被其他线程所修改。
如果比较内存中值与线程存的旧值不相等,说明已经被其他线程所修改过了,此时修改失败,需要采用自旋机制,重新获取到最新的共享变量的值,然后重新走一遍CAS流程。

Unsafe类

jdk的CAS机制有Unsafe类调用底层操作系统所实现,相关方法如下:

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

Unsafe类还有很多操作底层的功能,如操作系统的内存分配等等。但是Unsafe构造方法是私有的,所以只能通过反射获取。有关Unsafe类的其他作用和详解,可参考文章:java中的Unsafe

CAS存在问题

ABA问题
如果一个变量初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其它线程修改过了吗?如果这段期间它的值曾经被改成了B,然后又改回A,那么CAS操作就会误认为它从来没有被修改过。这个漏洞称为CAS操作的ABA问题。java.util.concurrent包为了解决这个问题,提供了一个带有标记性的原子引用类AtomicStampedRenference,它可以通过控制变量值的版本来保证CAS的正确性。不过目前来说这个类比较鸡肋,大部分情况下ABA问题并不会影响程序并发的正确性,如果需要解决ABA问题,使用传统的互斥同步可能回避原子类更加高效。

有限性
一次CAS指令只能控制一个变量,不能控制多个变量,如果想保证多个变量的安全性,则需要多个CAS指令,或者将多个变量组成一个对象,将对象进行CAS操作。

效率问题
效率问题:前面提到,如果存在多个线程竞争,可能导致CAS失败,此时可能需要循环(自旋)执行CAS,竞争激烈情况下会对性能有一定影响;

Atomic相关类解析

Atomic类采用CAS机制,保证并发安全,下面以AtomicInteger为例,分析使用和原理:

//原子设置为给定值并返回旧值。
public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
//如果当前值==预期值,则原子地将该值设置为给定的更新值。
public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
//当前值原子递增一
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

//原子地将当前值减少一
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

等等一系列原子操作,都是利用了CAS原理。保证在多线程环境下,对一个变量的操作保证安全性。
其他相关原子操作类:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的小小酥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值