CAS原理

    技术2022-07-10  164

    CAS是什么: CAS是CPU并发原语,由于CAS是系统原语,由若干条指令组成,而且原语在执行的过程中必须是一致的,所以CAS是线程安全的。CAS算法是一种无锁算法,但是CAS可以理解成不同于synchronouse的乐观锁。 CAS基本原理: CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

    //代码模拟简易过程 AtomicInteger atomicInteger = new AtomicInteger(10); // 10为期望值(A),1为新值(B) // 将主内存的值修改为1 修改成功,主内存值为1(V) atomicInteger.compareAndSet(10, 1) // 主内存的值为1 ,但是当前期望值是10,那么V和A值不同,修改失败 atomicInteger.compareAndSet(10, 2)

    CAS底层原理: CAS会把当前工作内存中的值和主内存中的值相比较,如果相同则执行后续操作,否者继续自旋偏移取主内存的值比较,直到主内存和工作内存的值一致为止。 基于jdk1.8.0_20 部分源码

    //Unsafe是CAS的核心类,Java无法操作底层系统,Unsafe就可以操作底层(Unsafe内部方法由native修饰) //此方法块的意思就是获取value值在工作内存中的偏移量valueOffset private static final Unsafe unsafe = Unsafe.getUnsafe(); static { try { //假如线程1和线程2都从主内存获取的变量值为10,先通过此方法获取10在工作内存的偏移量 valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value")); } catch (Exception ex) { throw new Error(ex); } } //通过valueOffset,直接通过内存地址,获取到值,然后把主内存值加20 public final int getAndIncrement() { return unsafe.getAndAddInt(this, valueOffset, 20); } //var1为this,AtomicInteger对象本身 //var2为valueOffset //var4为要增加的值 public final int getAndAddInt(Object var1, long var2, int var4) { int var5; do { //通过对象和valueOffset拿到主内存中真实的值(var5) var5 = this.getIntVolatile(var1, var2); //执行compareAndSwapInt比较工作内存中的值和主内存的值是否相等 //如果主内存中的值(var5)=工作内存的值value,则将值设为var5+var4,并返回true,否则返回false //假如线程1执行完毕了,返回了true,那么主内存的值就变成了30,那么线程2的工作内存的值还是10,而主内存是30,显然他们不相等,就返回false,执行执行do-while循环重新获取主内存的值 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }

    CAS缺点: ABA问题(CAS每次更新主内存的值之前都会拿之前从主内存取的值A和现在从主内存取的值B相比较,如果一致就更新,不一致就不更新,可以通过增加版本号解决此问题) 循环时间长,开销大(它的自旋会导致开销大) 无法对多个共享变量保证原子性,只能对一个共享变量(对多个共享变量就要加锁了)

    Processed: 0.015, SQL: 9