java#CAS

CAS介绍

CAS 称 自旋锁,无锁, 比较并换,不用加锁也能保证原子性
CAS 的全称 为 Compare-And-Swap 它是一条CPU并发原语它的功能是判断内存某个位置的值是          否为预期值,如果是则更改为新的值,这个过程是原子

CAS原理


     CAS操作由三个参数组成:内存地址V、期望值A和新值B。CAS操作的基本流程如下:
读取内存地址V中的当前值C。
如果C等于期望值A,则将新值B写入内存地址V中。
如果C不等于期望值A,则不做任何处理

CAS实现


    CAS并发原语体现在JAVA语言中就sum.misc.Unsafe类中的各个方法。调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用范畴,是由若干条指令组成的,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。


Unsafe类


     Unsafe 是CAS的核心类,由于java方法无法直接访问底层系统,需要通过本地(native)方法来访问,Unsafe 相当于一个后门
,基于该类可能直接操作特定内存的数据,Unsafe 类存在于sum.misc 包中,其内部操作可以像C的指针一样直接操作内存,因为java
中CAS操作的执行依赖于Unsafe类的方法。
注意:Unsafe 类中的所有方法都是 (native)修饰的,也就是说Unsafe 类中的方法都直接调用操作系统底层资源执行相应任务。

Unsafe 类部分代码
atomicInteger.getAndIncrement()的原理: 在Java中最底层是CompareAndSwap ,无限自旋,比较和交换。

public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 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;
    }


CAS示例


  public static void main(String[] args) {
       AtomicInteger count=new AtomicInteger(5);
       System.out.print(count.compareAndSet(5,10)+"\t count"+count.get());
       System.out.print("\n"+count.compareAndSet(5,10)+"\t count"+count.get());
   }

结果:
true     count10
false     count10
Process finished with exit code 0

CAS缺点

1) CPU开销过大

在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很到的压力。

2) 不能保证代码块的原子性(只能保证一个共享变量的原子操作)

CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。

3) ABA问题 
1线程A从主内存中拿了一份值 , 假如是10 , 它在自己的工作空间中打算进行修改了 (还没修改)
2这时线程B抢占了线程A , 它从主内存中将10取出来了, 它给修改成了22 , 放回主内存中了 , 但是呢 ,它感觉修改的不满意 , 又去主内存把那个22又取出来了 , 又给改成了10 , 然后走了
3这时线程A 去进行比较并交换 , 发现工作内存值和主内存值(期望值)是一样的都是10 , 就成功修改了, 但是 ! 注意 ! 线程A并不知道这个值中途被其他线程修改了 ! ! !

你可能感兴趣的:(JAVA,java,python,开发语言)