Java并发之CAS

一、什么是CAS

  CAS(Compare And Swap,比较和交换),通常指的是这样一种原子操作:在修改某一个变量前,会先比较它内存中的值是否和期望的值一致,如果一致,就给它赋一个新值。CAS的比较判断、赋值操作,是一个不可分割的原子操作,并且这一操作是在硬件层面得到保障,在Intel处理器中,使用的是cmpxchg指令。

//v = 内存中的值,E = 期望值 
if(v == E){
    v = newValue;
}

二、Java中的CAS

Java中的CAS方法都是来自Unsafe类。
Java中提供了三种CAS方法:

// 第一个参数:对象的实例  第二个参数:内存偏移量  第三个参数:对比期望的值  第四个参数:字段的新值
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);
//CAS示例
public static void main(String[] args) {
    AtomicInteger atomicInteger = new AtomicInteger(1);
    //这个方法底层就是使用compareAndSwapInt()
    boolean b = atomicInteger.compareAndSet(1, 3);
    System.out.println("第一次修改的结果: "+b+ "修改后的值: " +atomicInteger.get());
    boolean b1 = atomicInteger.compareAndSet(1, 6);
    System.out.println("第二次修改的结果: "+b1+ "修改后的值: "+atomicInteger.get());
}

执行的结果:
执行结果

三、CAS缺陷

CAS的缺陷主要表现在以下三个方面:
1.在多线程竞争条件下,CAS操作失败,会进行自旋,如果竞争激烈,就会给CPU带来非常大的开销
2.CAS每次只能保证一个共享变量的原子操作
3.CAS会产生ABA问题

四、CAS的ABA问题

  当多个线程对一个共享变量进行操作时,其中一个线程将变量的值从1改为2,但是立刻又将值从2改为1,那么对于其它线程而言是不可知的,仍然可以将变量的值修改成功。
ABA示意图
public static void main(String[] args) {
    AtomicInteger atomicInteger = new AtomicInteger(1);

    new Thread(()->{
        int value = atomicInteger.get();
        log.debug("Thread1 read value:"+value);

        LockSupport.parkNanos(100L);
        //CAS操作将原值改为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);
        //CAS操作将原值改为2
        if(atomicInteger.compareAndSet(value,2)){
            log.debug("Thread2 update from "+value+"to 2");
            value = atomicInteger.get();
            log.debug("Thread2 read value:"+value);
            //CAS操作将原值改为1
            if(atomicInteger.compareAndSet(value,1)){
                log.debug("Thread2 update from "+value+"to 1");
            }
        }
    },"Thread2").start();

}

执行结果如下:
执行结果

五、ABA的解决方案

数据库中有个乐观锁,是基于版本控制实现数据同步的机制,当数据每修改一次,版本就会+1。
而Java中同样也提供了类似的工具类——AtomicStampedReference、AtomicMarkableReference
如图所示,就是这个类使用时核心参数:

AtomicStampedReference核心参数

public static void main(String[] args) {
    AtomicStampedReference atomicStampedReference = new AtomicStampedReference(1,1);
    int stamp = atomicStampedReference.getStamp();
    int reference = (int) atomicStampedReference.getReference();
    boolean b2 = atomicStampedReference.compareAndSet(reference, 2, stamp, stamp + 1);
    System.out.println("第一次操作的结果:"+b2+" reference的值:"+reference + " stamp的值:" +stamp);

    reference = (int) atomicStampedReference.getReference();
    boolean b3 = atomicStampedReference.compareAndSet(reference, reference + 1, stamp, stamp + 1);
    System.out.println("第二次操作的结果:"+b3+" reference的值:"+reference + " stamp的值:" +stamp);

}

执行的结果:
执行结果

你可能感兴趣的:(Java并发之CAS)