CAS原理详解

books 本文包含知识点

  • CAS是什么?
  • CAS应用场景及原理
  • CAS的不足

books 1.CAS是什么?

CAS是Compare And Swap的缩写,比较并更新,是非阻塞同步的实现原理,它是CPU硬件层面的一种指令,从CPU层面能保证"比较并更新"两个操作的原子性。CAS指令操作包括三个参数:内存值(内存地址值)V、预期值A、新值B,当CAS指令执行时,当且仅当预期值A和内存值V相同时,才更新内存值为B,否则就不执行更新,无论更新与否都会返回否会返回旧的内存值V,上述的处理过程是一个原子操作。用java代码等效实现一下CAS的执行过程:

/**
 * @description CAS等价代码
 **/
public class CASTest {

    //内存值
    private volatile int ramAddress;

    /**
     * @param exceptRecord 期望值
     * @return newRecord 新值
     **/
    public synchronized int compareAndSwap(int exceptRecord, int newRecord) {
        int oldRamAddress = ramAddress;
        if (oldRamAddress == exceptRecord) {
            ramAddress = newRecord;
        }
        return oldRamAddress;
    }
}

books 2.CAS应用场景及原理

  • 原子类:JUC包下的原子类,比如AtomicInteger原子类的incrementAndGet()方法
  • 并发容器:比如ConcurrentHashMap的put()方法
  • 乐观锁:比如数据库层面的乐观锁操作,我们通过版本号字段来实现

鉴于内存操作是非常敏感的,一不小心就可能搞挂机器,所以像CAS这样的CPU指令集去操作内存并没有向广大开发人员开放,在jdk中被封装在sun.misc.Unsafe类里面,主要体现在Unsafe类的compareAndSwapInt()、copareAndSwapLong()等几个方法包装提供,通过Unsafe工具类来直接操作内存。查看源码我们可以看到这几个方法都是native修饰符修饰的,表示本地方法,本地方法就是指方法的实现体不在当前文件,而是在用其它语言实现的文件中。下面以AtomicInteger原子类为例,简单剖析下源码:

//volatile修饰value变量,保证线程间可见性
private volatile int value;

static {
	try {
        //拿到内存地址,根据这个地址得到具体的内存值
		valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
	} catch (Exception var1) {
		throw new Error(var1);
	}
}

public final int incrementAndGet() {
	return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

public final int getAndAddInt(Object var1, long var2, int var4) {
	int var5;
	//无限循环重试预期值和旧内存值比较动作
	do {
		var5 = this.getIntVolatile(var1, var2);
	} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

	return var5;
}

//包装在Unsafe类中,从cpu层面保证原子性
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

books 3.CAS的不足

CAS存在逻辑漏洞,称为ABA问题:当一个变量V初次读取时是A值,这个时候被线程1改为了B值,又被线程2修改回了A,那么在准备赋值的时检测到它还是A值,CAS就会误认为它没有改变过。显然为了解决这个问题,我们可以加入版本号的概念,通过控制变量值的版本来保证CAS的正确性,比如J.U.C包下的AtomicStampedReference就可以实现,但是一般情况下CAS的这个逻辑漏洞并不会影响程序并发问题。


books 引申阅读:

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java CAS(Compare And Swap,比较并交换)是一种常用于多线程编程的原子操作。其主要作用是在多线程环境下保证变量的原子性和一致性,解决多线程竞争条件下的并发问题。 Java CAS原理是通过比较内存中的值与期望值是否相等来确定是否进行交换,其核心思想是利用硬件的原子性操作来实现并发的同步,而不需要使用锁(synchronized)等机制。 具体来说,CAS操作包含三个参数:内存地址、旧的预期值和新的值。 1. 首先,CAS会将当前内存地址中的值与旧的预期值进行比较,如果相等,则说明内存中的值未被其他线程修改。 2. 然后,CAS会使用新的值来更新内存地址中的值,完成交换操作。 3. 最后,CAS会返回旧的预期值,可以通过返回值进行判断操作是否成功。 需要注意的是,CAS是一种乐观的并发控制方式,它不会阻塞线程,而是通过不断重试的方式来保证操作的原子性。如果CAS操作失败,那么线程会重新读取内存中的值,并重新尝试进行CAS操作,直到成功为止。 然而,CAS也存在一些问题。首先,CAS需要频繁地读取和写入内存,这对内存带宽的要求较高;其次,由于CAS操作是无锁的,因此存在ABA问题,即在操作过程中,如果其他线程修改了预期值两次并恢复为原来的值,CAS操作无法察觉。 总之,Java CAS作为一种基于硬件支持的原子操作,可以在多线程环境下实现高效的同步控制,然而它也需要开发人员自行处理ABA问题以及确保程序的正确性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值