深入理解CAS

CAS(CompareandSwap)是一种乐观锁技术,常用于实现线程安全的原子操作。它包括比较和交换两个阶段,只有当内存地址的值与期望值相同时才会更新。Java中的Atomic类利用CAS来实现线程安全,但存在ABA问题、自旋开销和并发度限制。解决这些问题的方法包括使用带版本号的CAS和调整自旋策略等。
摘要由CSDN通过智能技术生成

什么是CAS

        CAS(Compare and Swap,比较并交换)是一种乐观锁技术,用于实现多线程环境下的原子操作。CAS操作包括三个参数:内存地址V、期望值A和新值B。当且仅当V的值等于A时,才将V的值设置为B,否则什么也不做。即针对一个变量,首 先比较它的内存值与某个期望值是否相同,如果相同,就给它赋一个新值。

CAS 的逻辑用伪代码描述如下:

if (value == expectedValue){
     2 value = newValue; 3
} 

         以上伪代码描述了一个由比较和赋值两阶段组成的复合操作。

        CAS操作是由硬件指令支持的,因此具有很高的性能和安全性。在Java中,CAS操作通常使用Atomic类来实现,例如AtomicIntegerAtomicLongAtomicReference等。

        CAS操作可以用于解决多线程环境下的竞态条件问题,例如计数器、队列、缓存等数据结构的实现。但是,CAS操作也存在一些限制,例如ABA问题、自旋开销大、并发度不高等,需要在使用时进行注意和处理。

CAS应用

在Java中,CAS操作是由Unsafe类提供支持的。Unsafe类是JDK中不稳定、不建议使用的类,但是它提供了一些底层操作方法,如CAS操作,用于支持Java并发编程。

 Unsafe类提供了几种针对不同类型变量的CAS操作,包括:

  1. compareAndSwapObject(Object obj, long offset, Object expect, Object update):用于对象引用类型的CAS操作。
  2. compareAndSwapInt(Object obj, long offset, int expect, int update):用于整型类型的CAS操作。
  3. compareAndSwapLong(Object obj, long offset, long expect, long update):用于长整型类型的CAS操作。

        它们都是 native 方法,由 Java 虚拟机提供具体实现,这意味着不同的 Java 虚拟机对它们的实现 可能会略有不同。

CAS操作通常通过Atomic类来实现,例如AtomicIntegerAtomicLongAtomicReference等。这些类提供了一系列原子操作方法,可以保证线程安全地进行加减、比较、设置等操作。

以下是一些常见的CAS操作方法:

  1. compareAndSet(expectedValue, newValue):如果当前值等于期望值,则将其设置为新值,并返回true;否则不做任何事情,并返回false。
  2. getAndIncrement():获取当前值,并将其增加1,返回增加前的值。
  3. getAndAdd(delta):获取当前值,并将其增加delta, 返回增加前的值。
  4. getAndSet(newValue):获取当前值,并将其设置为新值,返回设置前的值。

这些方法都是原子操作,可以确保线程安全。需要注意的是,在使用CAS操作时有可能会出现ABA问题(即在操作过程中值先被A修改成B,再被B修改成A),因此需要根据具体情况进行评估和处理。

CAS缺陷

  1. ABA问题:如果一个值在执行CAS操作前后都被改为了相同的值,那么CAS就可能误认为它没有发生改变。这种情况称为ABA问题。
    @Slf4j
    public class ABATest {
    
        public static void main(String[] args) {
            AtomicInteger atomicInteger = new AtomicInteger(1);
    
            new Thread(()->{
                int value = atomicInteger.get();
                log.debug("Thread1 read value: " + value);
    
                // 阻塞1s
                LockSupport.parkNanos(1000000000L);
    
                // Thread1通过CAS修改value值为3
                if (atomicInteger.compareAndSet(value, 3)) {
                    log.debug("Thread1 update from " + value + " to 3");
                } else {
                    log.debug("Thread1 update fail!");
                }
            },"Thread1").start();
    
            new Thread(()->{
                int value = atomicInteger.get();
                log.debug("Thread2 read value: " + value);
                // Thread2通过CAS修改value值为2
                if (atomicInteger.compareAndSet(value, 2)) {
                    log.debug("Thread2 update from " + value + " to 2");
    
                    // do something
                    value = atomicInteger.get();
                    log.debug("Thread2 read value: " + value);
                    // Thread2通过CAS修改value值为1
                    if (atomicInteger.compareAndSet(value, 1)) {
                        log.debug("Thread2 update from " + value + " to 1");
                    }
                }
            },"Thread2").start();
        }
  2. 自旋开销:CAS操作是基于忙等待的自旋机制实现的,如果长时间无法竞争到资源,则会一直循环等待,浪费CPU资源。
  3. 并发度不高:在高并发场景下,由于CAS操作需要修改共享变量的值,因此只能有一个线程获得锁,导致并发度不高。
  4. 无法保证公平性:由于CAS操作是基于忙等待的自旋机制实现的,因此不能保证线程获取锁的公平性。

针对上述问题,可以采取一些措施进行处理和优化,例如使用带版本号的CAS操作来解决ABA问题、设置自旋次数或者使用阻塞等待来避免自旋开销、使用分段锁或者其他锁机制提高并发度、使用公平锁来确保锁的公平性等。需要根据具体情况进行评估和处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值