CAS是什么
(CAS知道吗?)
CAS的全称为Compare-And-Swap,它是一条CPU并发短语
它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,这个过程是原子的
CAS并发原语体现在Java语言中就是sun.misc.Unsafe类中的各个方法,调用UnSafe类中的CAS方法,JVM会帮我们实现出CAS汇编指令。这是一种完全依赖于硬件的功能,通过它实现了原子操作。再次强调,由于CAS是一种系统原语,原语属于操作系统用语范畴,是由若干条指令组成的,用于完成某一个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,也就是说CAS是一条CPU的原子指令,不会造成所谓的数据不一致问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Co7WZqNh-1620402291798)(D:\ljwxy\陆君\笔记MD照片\多线程\CAS\Snipaste_2021-05-03_20-47-55.png)]
假设线程A和线程B两个线程同时执行getAndAddInt操作(分别跑在不同的CPU上)
- AtomicInteget里面的value原始值为3,即主内存中AtomicInteger的value为3,根据JMM内存模型,线程A和线程B各自持有一份值为3的value的副本分别到各自的工作内存。
- 线程A通过getIntVolatile(var1,var2)拿到value值3,这时线程A被挂起
- 线程B也通过getIntVolatile(var1,var2)方法获取到了value值3,此时刚好线程B没有被挂起并执行了compareAndSwapInt方法比较内存值也为3,成功修改内存值为4,线程B打完收工,一切OK
- 这时线程A恢复,执行compareAndSwapInt方法比较,发现自己手里的值数字3和主内存的值数字4不一致,说明该值已经被其他线程抢先一步修改过了,那A线程本次修改失败,只能重新读取重新来一遍了
- 线程A重新获取value值,因为变量value被volatile修饰,所以其他线程对它的修改,线程A总是能够看到,线程A继续执行compareAndSwapInt进行比较替换,知道成功
CAS得劣势
- 循环开销很大:我们可以看到getAndInt方法执行时,有个do while,如果CAS失败,会一直进行尝试,如果CAS长时间一直不成功,可能会给CPU带来很大得开销
- 只能保证一个共享变量得原子操作:当对一个共享变量执行操作时,我们可以使用循环CAS得方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作得原子性,这个时候就可以用锁来保证原子性
- 引发出来ABA问题
ABA是什么
(原子类AtomicInteger得ABA问题谈谈?原子更新引用知道吗?)
ABA:就是线程A修改过一个数据,不过在进行多次修改过后,有修改成了原数据,此时线程B接手,发现预算值和内存的值一致,但是已经多次操作了。
CAS——>UnSafe——>CAS底层思想——>ABA——原子引用更新——>如何规避ABA问题
//支持时间戳得普通原子引用
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
// 100:初始数据 1:初始版本 就时依靠版本来解决ABA问题得
static AtomicStampedReference<Integer> atomicStampedReference=new AtomicStampedReference<>(100,1)
=new AtomicStampedReference<>(100,1)
在每次修改数据得时候 不光要判断数据是否一致,还要判断版本号是否一致,版本号也一致 才算成功。