CAS

1:CAS是什么?

比较并交换 (compareAndSwap),是一条CPU并发原语,是乐观锁技术的一种实现,当多个线程尝试使用CAS同时修改同一个变量时,只有其中一个线程能修改变量的值,而其它线程都失败,失败的线程并不会被挂起或者结束,

而是继续尝试(循环比较)修改,直到修改成功

源码一览:

    public final int getAndAddInt(Object var1, long var2, int var4) {        int var5;        do {
//获取数据 var5
= this.getIntVolatile(var1, var2);
      //比较数据 v1和v2找到值 和v5做比较 }
while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4)); return var5; }

v1是当前对象,v2是内存地址偏移量,通过v1和v2可以查找到一个精确的数据并拷贝到自己线程工作区域内,然后根据这个数据和v5进行比较,只要是一致的,那么执行v5 + v4

当线程被切换过之后,那么此时,v5还是v5,但是v1和v2的值却不一定等于v5了,因为已经切换过其他线程,其他线程可能对这个v1和v2已经做了修改,如果做了修改,那么将继续循环比较,如此往复,直到成功

优点:

  1:不加锁,通过unSafe类解决数据一致性问题

  2:直接操作主内存 不存在数据不一致问题

  3:通过自旋锁方式,对数据进行比较和交换

缺点:

  1:自旋锁对cpu开销特别大

  2:只能保证一个共享变量的原子操作

  3:导致ABA问题

ABA问题:

  两个线程通过cas操作同一个变量,当T1线程和T2线程都获得主内存X的时候,T1的期望值是A想要修改成B,但是T2线程快速的将主内存A修改为任意值,然后又将任意值修改回A,此时T1再次获取主内存 值的时候发现 还是A就做了修改。表面上程序是正常运行的,但是这个过程中这个值是存在多变的,不保证这个过程没有问题!

代码示例:
import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicReference;public class test {    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);    public static void main(String[] args) {        new Thread(() -> {            atomicReference.compareAndSet(100,101);            atomicReference.compareAndSet(101,100);        },"t1").start();        new Thread(() -> {            try {                TimeUnit.SECONDS.sleep(2);                                //在本次修改之前 其实数据已经被修改过,但是此处只做第一次和最后一次的比较,发现100=100,所以就直接继续修改完成                System.out.println(atomicReference.compareAndSet(100, 2000) + " 	 getVaue:" + atomicReference.get());            }catch (Exception d){                d.printStackTrace();            }        },"t2").start();    }}

 

解决ABA问题:

  通过 AtomicStampedReference来添加版号作为修改的依据,如下代码,只要ABA发生,数据则修改失败!

import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicReference;import java.util.concurrent.atomic.AtomicStampedReference;public class test {    static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);    static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);    public static void main(String[] args) {        new Thread(() -> {            atomicReference.compareAndSet(100,101);            atomicReference.compareAndSet(101,100);        },"t1").start();        new Thread(() -> {            try {                TimeUnit.SECONDS.sleep(2);                System.out.println(atomicReference.compareAndSet(100, 2000) + " 	 getVaue:" + atomicReference.get());            }catch (Exception d){                d.printStackTrace();            }  新疆干部培训 http://xj.ganxun.cn/        },"t2").start();        //处理ABA问题        new Thread(() -> {            try {                TimeUnit.SECONDS.sleep(3);            }catch (Exception e){                e.printStackTrace();            }            atomicStampedReference.compareAndSet(100,200,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);            atomicStampedReference.compareAndSet(200,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);        },"t3").start();        new Thread(() -> {            int stamp = atomicStampedReference.getStamp();            try {                TimeUnit.SECONDS.sleep(3);            }catch (Exception e){                e.printStackTrace();            }            boolean b = atomicStampedReference.compareAndSet(100, 500, stamp, stamp + 1);            System.out.println(Thread.currentThread().getName() + " 	 版本号:" + stamp + ",当前版本号: "+atomicStampedReference.getStamp()+"修改结果:" + b                    + ",实际值是:" + atomicStampedReference.getReference());        },"t4").start();    }}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值