CAS

CAS详解

1.CAS

cas通俗点说就是比较和交换,synchronized是一种悲观锁,那么cas就是乐观锁;

悲观锁:就是线程独占,只有当这个线程结束,才能有其它线程使用

乐观锁:乐观锁就是不加锁,假设没有冲突,而完成某项操作,如果冲突失败就重试

2.CAS的底层思想

实例:

 1 public class CASdemo {
 2     public static void main(String[] args) {
 3      AtomicInteger atomicInteger=new AtomicInteger(0);
 4         for (int i = 0; i <20 ; i++) {
 5             new Thread(()->{
 6                 for (int j = 0; j <100 ; j++) {
 7                     atomicInteger.getAndIncrement();
 8                 }
 9             },String.valueOf(i)).start();
10         }
11 12         try{
13             TimeUnit.SECONDS.sleep(3);//估计3秒上面的20个线程跑完
14         }catch (InterruptedException e){
15             e.printStackTrace();
16         }
17         System.out.println(atomicInteger.get());
18     }
19 }

 


原子类AtomicInteger源码:

1 //成员变量Volatile保证了可见性,以及禁止指令重排
2 private volatile int value;
3 4 //++方法
5   public final int getAndIncrement() {
6         return unsafe.getAndAddInt(this, valueOffset, 1);
7     }
8 9

 

unSafe类

 1 //var1为对象 var2就是value内存偏移量就是的内存地址,
 2  public final int getAndAddInt(Object var1, long var2, int var4) {
 3         int var5;
 4         do {
 5             //到var1这个对象,var2位置拿值
 6             var5 = this.getIntVolatile(var1, var2);
 7         } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//这个方法,是先判断现在拿到的值,是不是还是那个值,如果是,就替换,返回true,自旋结束,否则false,重新拿值;这就是一种乐观锁
 8         return var5;
 9     }
10 11 //下面这两个方法都是本地方法,它们的底层都是C++实现的,是系统的原语,具有原子性
12 public native int getIntVolatile(Object var1, long var2);
13  public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

 

 

4.CAS缺点

1.循环时间长开销时间大

有一个自旋,所以时间开销大

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

只能保证一个对象

3.ABA问题

例子:

 1 AtomicInteger a=new AtomicInteger(0);
 2 a=0;
 3  4 //假如线程1运行时间是20,将a变为10
 5 //线程2运行时间是5,将a变为5或0;
 6  7 //当线程运行时
 8 //线程1运行 此时拿到a=0
 9 //线程2运行 将a变为5   时间过5
10 //线程2再次运行 将a变为0 时间过5
11 //时间过10 ,到线程1要写值时a=0余主内存a=0一致将 a=10写入
12 13 //此时a已经被改写过,只不过还是原来的值,但是线程1不知道,这就是aba的问题

 

如何规避这个ABA问题?

简单直接,加个时间戳

代码实例:

 1 class User{
 2     String name;
 3     byte age;
 4 }
 5 public class ABAdemo {
 6     public static void main(String[] args) {
 7         User A=new User();
 8         A.name="A";
 9         A.age=18;
10         User B=new User();
11         B.name="B";
12         B.age=20;
13         //一个对象,1为版本号
14  AtomicStampedReference<User> atomicStampedReference = new AtomicStampedReference<>(A,1);
15         System.out.println("获得对象"+atomicStampedReference.getReference());
16         
17         //对象比对,版本号比对
18         atomicStampedReference.compareAndSet(A,B,1,2);
19         System.out.println("修改后"+atomicStampedReference.getReference());
20     }
21 }

 

 

 

posted @ 2019-07-19 22:11  胡萝卜88号  阅读(192)  评论(0)    收藏  举报